JavaScript Is element before or after another element in DOM

Yes, sort of. DOM3 introduced Node.compareDocumentPosition, which allows you to compare the position of two elements. The functionality isn't very friendly: it involves bitmasks: this is a jQuery plugin that should simplify its use.

This code is only tested on Firefox 9 and the current version of Chromium. Certainly it won't work in old versions of IE.

$.fn.docPosition = function(element) {
    if (element.jquery) element = element[0];

    var position = this[0].compareDocumentPosition(element);

    if (position & 0x04) return 'after';
    if (position & 0x02) return 'before';
};

Also, an element that contains another is considered to be before it in the structure.


OK, a little Googling gives me this blog post by John Resig (the creator of jQuery), which includes compatibility with IE <9. (It's a little ugly: it uses two non-standard bits of functionality: contains and sourceIndex.) This code should be cross-browser:

$.fn.docPosition = function (element) {
    function comparePosition(a, b) {
        return a.compareDocumentPosition ? 
          a.compareDocumentPosition(b) : 
          a.contains ? 
            (a != b && a.contains(b) && 16) + 
              (a != b && b.contains(a) && 8) + 
              (a.sourceIndex >= 0 && b.sourceIndex >= 0 ?
                (a.sourceIndex < b.sourceIndex && 4) + 
                  (a.sourceIndex > b.sourceIndex && 2) :
                1)
            + 0 : 0;
    }

    if (element.jquery) element = element[0];

    var position = comparePosition(this[0], element);

    if (position & 0x04) return 'after';
    if (position & 0x02) return 'before';
};
Answer:1

A brute force approach may be to get all elements, then get the index of each element within the set.

var all = $('*');

var a_index = all.index($('#element_a'));
var b_index = all.index($('#element_b'));

if( a_index < b_index ) 
    alert( 'a is first' );
else
    alert( 'b is first' );

For a browser compliant non-jQuery solution, you could do this:

function sortInDocumentOrder( a, b ) {
    var all = document.getElementsByTagName('*');

    for( var i = 0; i < all.length; ++i ) {
        if( all[i] === a )
            return [a,b];  
        else if( all[i] === b )
            return [b,a];
    }
}

Give it two elements, and it will return them in the document order.

var a = document.getElementById('a');
var b = document.getElementById('b');

var inOrder = sortInDocumentOrder( a, b );
Answer:2

You're confusing a few things. The location in markup is the location in the DOM. This line shows your confusion:

<x><y /></x> //not really before or after is it?

Of course y is after x by any reasonable definition. You should think of the DOM as a tree, not as characters in a text file.

Now, as for determining position, use Node.compareDocumentPosition:

node.compareDocumentPosition(otherNode)

The return value is a bitmask with the following values:

DOCUMENT_POSITION_DISCONNECTED = 0x01;
DOCUMENT_POSITION_PRECEDING = 0x02;
DOCUMENT_POSITION_FOLLOWING = 0x04;
DOCUMENT_POSITION_CONTAINS = 0x08;
DOCUMENT_POSITION_CONTAINED_BY = 0x16;
Answer:3

I don't have complete code, but the approach I would take (if Node.compareDocumentPosition isn't available) is:

  1. obtain the .parents() chain of both elements
  2. find the element furthest up each chain that's in both chains - this is the common parent
  3. then check for the next element down each chain whether its index is before or after the other

There are tricks you could use to make (1) and (2) simpler by having the DOM do some of the work for you:

var $a = $('#a'); // first element
var $b = $('#b'); // first element

$a.parents().andSelf().addClass('search'); // mark A and all of A's ancestors
var $parent = $b.closest('.search');       // find B's first marked ancestor
Answer:4

This question requires a set of rules on what is considered before and after. It's certainly easy to traverse the elements in body and see what comes next, but is there any sort of hierarchical precedence? What about repeating elements?

<foo>
   <bar>
       <foobar />
   </bar>
</foo>
<foo>
   <baz />
</foo>
<foobar />

Does baz come before foobar?

I'd create two functions isBefore and isAfter; in this case they'd both be true (doing a depth first lookup).


var el = $('*');

function isBefore(elA, elB){
   return ( el.index($(elA).first()) < el.index($(elB).last()) );
}

function isAfter(elA, elB){
   return ( el.index($(elA).last()) > el.index($(elB).first()) );
}


isBefore('body', 'head'); // false
isAfter('body', 'head');  // true
Answer:5

I'm relativly new to Backbone.js I have a JSON like the picture shows ! I saw some Answers in relation with Backbone-relational, but still dont get the point! How can i convert this JSON to ...

I'm relativly new to Backbone.js I have a JSON like the picture shows ! I saw some Answers in relation with Backbone-relational, but still dont get the point! How can i convert this JSON to ...

I'm currently researching a way to produce non-photorealistic rendering in webgl. The best looking algorithm I've found so far for edge detection was implemented with OpenGL's geometry shader, here. ...

I'm currently researching a way to produce non-photorealistic rendering in webgl. The best looking algorithm I've found so far for edge detection was implemented with OpenGL's geometry shader, here. ...

Weird little snafu. I'm using jQuery's .css() method to change the size of text (long story; no, I can't use media queries) using a variable and I need to add em to it. I'm not sure what the syntax is ...

Weird little snafu. I'm using jQuery's .css() method to change the size of text (long story; no, I can't use media queries) using a variable and I need to add em to it. I'm not sure what the syntax is ...

  1. jquery function multiple variable
  2. jquery function multiple parameter

I'm following a tutorial on importing and displaying images on an HTML5 canvas. Everything works fine, until I try to change the image itself. For example, I'll have a yellow circle as my image, and ...

I'm following a tutorial on importing and displaying images on an HTML5 canvas. Everything works fine, until I try to change the image itself. For example, I'll have a yellow circle as my image, and ...