Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at the New York ColdFusion User Group (Apr. 2008) with: Rob Gonda
Ben Nadel at the New York ColdFusion User Group (Apr. 2008) with: Rob Gonda@RobGonda )

Using Node.contains() To Determine If One DOM Node Is Inside Another

By Ben Nadel on

This post is primarily a "Note to Self"; but, the other day, I was reading through the Mozilla Developer Network (MDN) site - as you do - and I noticed that the Node interface in the Document Object Model (DOM) API has a .contains() method. This method checks to see if one node is contained within, or is equal to, another node. In jQuery, I used to use the .contains() method all the time for this type of investigation. However, when it came to the native DOM, I've historically walked up the tree comparing object references. I'm shocked that I didn't know that the native DOM API contained a similar helper. As such, I'm documenting it here in an effort to drive this information into my head.


 
 
 

 
 
 
 
 

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

As you can see from earlier posts, like "Tracking Click Events Outside The Current Component In Angular 2 Beta 1", if I wanted to compare the relative relationship of two nodes in the DOM, I would start at one node and continue walking up the parentNode chain until the two references were the same; or, until I ran out of parentNode references to inspect. Such an approach looked something like this:

  • function isLocalNode( node, target ) {
  •  
  • do {
  •  
  • if ( node === target ) {
  •  
  • return( true );
  •  
  • }
  •  
  • target = target.parentNode;
  •  
  • } while ( target );
  •  
  • return( false );
  •  
  • }

This worked well. And, it wasn't all that complicated. But, it turns out that I can completely offload this logic to the native Node.contains() method. To see this in action, I've created a simple demo in which you can click anywhere in the page and I'll log to the console whether or not the target node is local to a known container:

  • <!doctype html>
  • <html lang="en">
  • <head>
  • <meta charset="utf-8" />
  • <title>
  • Using Node.contains() To Determine If One DOM Node Is Inside Another
  • </title>
  •  
  • <link rel="stylesheet" type="text/css" href="./demo.css">
  • </head>
  • <body>
  •  
  • <h1>
  • Using Node.contains() To Determine If One DOM Node Is Inside Another
  • </h1>
  •  
  • <p>
  • This node is <strong>outside</strong> the <em>red node</em>.
  • </p>
  •  
  • <div class="container">
  • <p>
  • This node is <strong>inside</strong> the <em>red node</em>.
  • </p>
  •  
  • <blockquote>
  • <p>
  • <em>As is <u>this one</u>!</em>
  • </p>
  • </blockquote>
  • </div>
  •  
  • <p>
  • This node is <strong>outside</strong> the <em>red node</em>.
  • </p>
  •  
  • <script type="text/javascript">
  •  
  • var container = document.querySelector( "div.container" );
  •  
  • // For the demo, we're going to use event-delegation on the document in order to
  • // allow the user to select any element on the page.
  • document.addEventListener( "click", handleClick, false );
  •  
  • // --------------------------------------------------------------------------- //
  • // --------------------------------------------------------------------------- //
  •  
  • // I handle the event-delegation and check for the relative node relationship.
  • function handleClick( event ) {
  •  
  • console.group( "Checking Containership" );
  • console.log( "Container:", container );
  • console.log( "Target:", event.target );
  • console.log( "Is Local:", isLocalNode( container, event.target ) );
  • console.groupEnd();
  •  
  • }
  •  
  • // I determine if the given target is equal-to or contained within the given node.
  • function isLocalNode( node, target ) {
  •  
  • // In Internet Explorer (IE), Node.contains() only works on Element nodes,
  • // not Text nodes. As such, let's travel up to the nearest Element node.
  • // --
  • // NOTE: This doesn't necessarily apply to this demo, which only reacts to
  • // Element node interactions. However, I'm adding it here as a mental note.
  • while ( target && ( target.nodeType !== Node.ELEMENT_NODE ) ) {
  •  
  • target = target.parentNode;
  •  
  • }
  •  
  • return( node.contains( target ) );
  •  
  • }
  •  
  • </script>
  •  
  • </body>
  • </html>

As you can see, I'm using event-delegation to handle the click event. Then, taking the target of the click event, I'm using the Node.contains() method to see if the click target is contained within (or is equal to) the given container.

In this case, I'm ensuring that the target node is an Element node. While this demo only allows for Element node selection, I've added this one additional piece of logic as a mental note for Internet Explorer (IE) 11. I came across the Node.contains() method while playing with the Selection API. And, when selecting text, it's easy to end up with a Text node instead of an Element node. And, in IE, the Node.contains() method only works for Element nodes.

That said, if we run this code in the browser and click outside and then inside the red box, we get the following output:


 
 
 

 
 Using the Node.contians() method to check containership. 
 
 
 

As you can see, we were able to use the Node.contains() method to check if the click target Element was contained within (or was equal to) the given container.

Hopefully, after writing this up, it will stick in my head!



Looking For A New Job?

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.