Node.contains: Check if a Node is a Child of Another Node

By  on  

There are loads of basic, native JavaScript methods that many developers don't know about.  Many people don't know about the Element.classList API, for example, so className management becomes another case for needing a JavaScript toolkit for even the most basic tasks.  Another case is checking for node parenting -- developers believe it requires a toolkit or a loop checking parentNode up the chain;  no so!  Nodes provide a contains method to check if one node if a parent of another:

function(parentNode, childNode) {
	if('contains' in parentNode) {
		return parentNode.contains(childNode);
	}
	else {
		return parentNode.compareDocumentPosition(childNode) % 16;
	}
}

You'll note we check for the contains method before using it, as you would probably expect, and use the rarely-known compareDocumentPosition in the case that contains isn't supported (Firefox < 9).  This method would be helpful when creating a drag & drop widget and determining moves between lists.  Anyways, before you jump to the conclusion that you need a toolkit for something that seems basic, do some quick research and hopefully you find an easier way!

Recent Features

  • By
    Create a Sheen Logo Effect with CSS

    I was inspired when I first saw Addy Osmani's original ShineTime blog post.  The hover sheen effect is simple but awesome.  When I started my blog redesign, I really wanted to use a sheen effect with my logo.  Using two HTML elements and...

  • By
    Serving Fonts from CDN

    For maximum performance, we all know we must put our assets on CDN (another domain).  Along with those assets are custom web fonts.  Unfortunately custom web fonts via CDN (or any cross-domain font request) don't work in Firefox or Internet Explorer (correctly so, by spec) though...

Incredible Demos

  • By
    jQuery Wookmark

    The first thing that hits you when you visit Pinterest is "Whoa, the columns are the same width and the photos are cut to fit just the way they should."  Basic web users probably think nothing of it but as a developer, I can appreciate the...

  • By
    Create Your Own Dijit CSS Theme with LESS CSS

    The Dojo Toolkit seems to just get better and better.  One of the new additions in Dojo 1.6 was the use of LESS CSS to create Dijit themes.  The move to using LESS is a brilliant one because it makes creating your own Dijit theme...

Discussion

  1. MaxArt

    I’m not sure this works. Shouldn’t the function always return a boolean?

    If I compare an element with one of its children, with compareDocumentPosition I get 4. If I compare an element with its parent, I get 2.

    That’s how I used to polyfill the function:

    // 16 === Node.DOCUMENT_POSITION_CONTAINED_BY
    Node.prototype.contains = function(node) {
        return (this.compareDocumentPosition(node) & 16) !== 0 || this === node;
    }
    
    • Nick Williams

      You’re right, compareDocumentPosition returns a bitmask, so it can represent multiple values at once. e.g.

      var parent = document.createElement("div");
      var child = document.createElement("div");
      parent.appendChild(child);
      
      // as the article has it
      parent.compareDocumentPosition(child) % 8; // 4, truthy
      child.compareDocumentPosition(parent) % 8; // 2, truthy
      
      // how it should be
      parent.compareDocumentPosition(child) & 16; // 16, truthy
      child.compareDocumentPosition(parent) & 16; // 0, falsy
      

      John Resig’s article covers this in detail: http://ejohn.org/blog/comparing-document-position/

    • Updated, thank you!

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!