Chris
Chris

Reputation: 7853

Finding the element with the lowest depth

I have a DOM structure like this:

<div id="one" class="center">
    <div id="two" class="wrap">
        <div id="three" class="west">
            <div id="four" class="center"></div>
        </div>
        <div id="five" class="center"></div>
    </div>    
</div>

It's about a automatically generated layout. Now i'd like to adress specific elements like a path but ignore all "wrap" elments in between.

For example:

  1. center/center should yield #five
  2. center/west should yield #three
  3. center/west/center should yield #four

I tried using two different selectors:

$('.center .center') but instead of returning #five it returns [#four, #five] which is of course correct for this selector but not what i want here.

$('.center > .center') this one returns #five which is what i want but when i try to apply the same form of selector to (2.) or (3.) like this: $('.center > .west') it will return nothing because of the .wrap element in between.

So a long explanation for a simple question. Is there a way to get something like:

$('.center .center').lowestDepth()

Upvotes: 1

Views: 149

Answers (2)

MrVentzi
MrVentzi

Reputation: 669

EDIT2: Sorted it.

EDIT: Just noticed it's not actually doing it the way I expected it :D will try to improve and update.

I've come up with a solution. It works for the current structure, but haven't tested with different structure:

function findStuff(arg1, arg2, arg3) {
if ($('.' + arg1).children('.' + arg2).length == 0) {
    if ($('.' + arg1).children().first().attr('class') != arg2) {
        if(arg3 == null) {
            findStuff($('.' + arg1).children().first().attr('class'), arg2, null);
        } else {
            findStuff($('.' + arg1).children().first().attr('class'), arg2, arg3);
        }     
    }
} else {        
    if(arg3 != null) {
        findStuff(arg2, arg3, null); 
    } else {
        $('.' + arg1).children('.' + arg2).css('background-color', 'red'); 
    }
}
}
$(document).ready(function () {
findStuff("center", "center", null);
});

https://jsfiddle.net/vhs4c0cp/1/

First it looks for the first 2 sets of arguments and if there is a third argument, once the first element matching the original arg1 and arg2 is found, it will call itself with 2 new arguments.

Upvotes: 1

GNi33
GNi33

Reputation: 4509

There is not really a built-in function in jQuery to do this out of the box, the .closest - method is somewhat similar, it just traverses up the DOM.

What you could do is call a function recursively and filter on the direct childs of an element and do so, until you found your closest element.

I made a quick jsFiddle to show this.

function lowestDepth(selector, elem){
    var childElements = elem.children();

    var filteredElements = childElements.filter(selector);

    if(filteredElements.length === 0){
       return lowestDepth(selector, childElements);
    } else {
       return filteredElements.eq(0);
    }
}


var elements = $('#one .west');
var ldelement = lowestDepth('.center', elements);

.children() traverses one level down in the DOM and returns matched elements, you could even pass a selector to it to filter elements in the same step, but I think the example is clearer this way.

The elements variable defines the "starting point", the first argument passed is the selector that the function looks for.

Note that this is a quick example to show you the idea behind this, this could be polished and optimized.

Upvotes: 1

Related Questions