Skip to content Skip to sidebar Skip to footer

Sort Array Containing DOM Elements According To Their Position In The DOM

Context I've structured a jQuery plugin I'm currently working on in a way that has me storing DOM elements in an array, mostly for being able to store more information next to thes

Solution 1:

There is a very useful function called compareDocumentPosition, which returns a number based on where two elements are relative to each other. You can use this in a .sort callback:

yourArray.sort(function(a,b) {
    if( a === b) return 0;
    if( !a.compareDocumentPosition) {
        // support for IE8 and below
        return a.sourceIndex - b.sourceIndex;
    }
    if( a.compareDocumentPosition(b) & 2) {
        // b comes before a
        return 1;
    }
    return -1;
});

Solution 2:

While I don't suggest you go with this approach, it is possible with jquery to get a "global DOM index":

var $all = $("*");

// use index to get your element's index within the entire DOM
$all.index($YOUR_EL);

Solution 3:

You don't have to do a lot of refactoring to take advantage of jQuery's sorting. You can use it as a temporary sorting mechanism. Here's an off-the-cuff:

function putInDocumentOrder(a) {
      var elements;

    // Get elements in order and remember the index of
    // the entry in `a`
    elements = $().add(a.map(function(entry, index){
        entry.element.__index = index;
        return entry.element;
    }));

    // Build array of entries in element order
    a = elements.map(function(){
        return a[this.__index];
    }).get();

    return a;
}

It requires an expando, but it does the job. Live Example

This has the advantage that it works on all browsers that jQuery supports, rather than your having to deal with the edge cases (IE8 not supporting compareDocumentPosition, for instance) yourself.


Solution 4:

If you can assume that the visible location on the page is the same, that could be a relatively quick solution:

function compareByVisibleLocation(a, b) {
  if (a.offsetTop > b.offsetTop) {
    return 1;
  } else if (a.offsetTop < b.offsetTop) {
    return -1;
  }

  if (a.offsetLeft > b.offsetLeft) {
    return 1;
  } else if (a.offsetLeft < b.offsetLeft) {
    return -1;
  } else {
    return 0;
  }
}

nodes.sort(compareByVisibleLocation);

Else, you can use querySelectorAll() to quickly build an index (it's a depth-first pre-order traversal) either by explicitly marking the nodes you want to index with an indexed-node classname.

var nodes = document.querySelectorAll('.indexed-node');

Or by grabbing all of a single node type, if that's works:

var nodes = document.querySelectorAll('div');

Or by just grabbing all nodes:

var nodes = document.querySelectorAll('*');

And then adding an index attribute to each node:

for (var i = 0; i < nodes.length; i++) { nodes[i].__DomIndex = i; }

You can sort like this then:

var nodes = yourGetMethod().sort(function(a,b) {
  if (a === b) {
    return 0;
  } else if (a.__DomIndex > b.__DomIndex) {
    return 1;
  } else {
    return -1;
  }
});

Should work down to IE8.


Post a Comment for "Sort Array Containing DOM Elements According To Their Position In The DOM"