(PLEASE NO JQUERY)
Let's say I have the following tree. I want to iterate over elements that match querySelectorAll('div.bar')
starting from div.foo
, but not over children that match the same selector. How do I do that?
div.foo
div.bar -- select
div.bar -- select
div.bar -- skip
div.bar -- skip
div.damnSon
div.bar -- select
div.bar -- select
div.bar --skip
div.bar -- select
div.bar -- skip
TreeWalker
is a no-go because
NodeIterator
don't work either because of the same issues and it iterates over children all the same, even when you reject the parent.Most ideal case would be to somehow get the result of querySelector
that isn't flat. Then I'd just loop over them without having to concern myself with nested properties.
So far I have come up with the following alcoholic method:
let nodeIterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT);
let node;
while(node = nodeIterator.nextNode()){
if (node.matches('.bar .bar')) {
//skip
} else if (node.matches('.bar')) {
//do things
}
}
The problems with this are:
div.foo
(i.e. my root element) is itself nested inside (div.bar
)If anyone can advise a better method, that'd be much appreciated.
UPDATE: Ok so I came up with the following method, that sort of solves the last point without being that much more inefficient:
let bars = root.getElementsByClassName('bar');
let excludedChildren = [];
for(let i = 0; i < bars.length; i++){
let children = bars[i].getElementsByClassName('bar');
if(children.length>0) Array.prototype.push.apply(excludedChildren, children);
}
bars = bars.filter(e=>!excludedChildren.includes(e));
bars.forEach(e=>{
//do stuff
});
UPDATE: Time to close this old sh*t up, here is my final solution. Has worked for a month now in production without any problems. Of course this will not be able to handle some very complex cases, but it's extensible.