Randy Hall
Randy Hall

Reputation: 8167

Get target element's (numeric) dom hierarchy javascript

No library solutions, please, though if you know of one that does this, I'm happy to take a look at how they do it. Not terribly concerned with fall-backs and cross browser support.

I have a hierarchy (that will change):

<body>
    <div></div>
    <div>
        <div></div>
        <div></div>
        <div>
            <a>Click Me!</a>
        </div>
    </div>
</body>

I have an event listener on <a>Click Me!</a> and get an event object back. That much works. YEY!

I want the event.target dom hierarchy numerical index. basically, [0][1][2][0] (though it would probably return as an array, [0,1,2,0], and that's okay with me).

I know this can be done with iterating through the parent elements. I'm trying to avoid that iteration, if possible.

EDIT Redacting my last edit as an act of idiocy.

Upvotes: 2

Views: 3797

Answers (3)

Christophe
Christophe

Reputation: 28174

A way to get an index without explicit iteration is to use the array indexOf method.

Here is what it would look like, e being your event:

function getIndex(e){
  var t=e.target;
  return Array.prototype.indexOf.call(t.parentNode.childNodes,t);
}

There's a number of gotchas with this technique. First, indexOf is only supported by the most recent browsers. Second, you need the call trick because a NodeList is not an array. Third, childNodes might return more nodes than expected and then you'll have to filter by node type.

To get the whole hierarchy index, just rince and repeat as you climb up the DOM hierarchy with parentNode.

For the record, e.target is not cross-browser either, but I see this is what you're already using.

[Update] The full code, using children instead of childNodes:

function getIndex(e) {
var index=[],
    t=e.target;

while (t!==document.body) {
    index.unshift(Array.prototype.indexOf.call(t.parentElement.children,t));
    t=t.parentElement;
}
return index;
}

Upvotes: 6

Christophe
Christophe

Reputation: 28174

You say that "The elements will dynamically change on the page quite rapidly" and that you are "attempting to create an array in javascript that mimics the position of elements in the dom". It means that you'll need to recalculate not only the index path of the element(s) that moved, but also the index path of the ones that didn't move.

Bottom line: instead of calculating the path of an individual element, it makes sense to me to iterate through the whole hierarchy, as anyway you'll need to recalculate not one, but all index paths.

Upvotes: 1

Kyle Campbell
Kyle Campbell

Reputation: 186

I know you want to avoid iteration, but it's probably the most straight forward strategy:

$(document).on('click','a', function(e){
  var result=[];
  var count = function(e){
    if(e.parentNode != document.body ){
      result.push(e);
      count(e.parentNode);
   }else {
      return result;                                    
   }
 };
 count(e.target)
 console.log(result);
});

For what reasons are you trying to avoid iteration? Is the dom huge or something?

Upvotes: 3

Related Questions