Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery filtering selector to remove nested elements matching pattern

Given this sample markup (assuming a random number of elements between .outer and .inner:

<div class="outer">
    <div>
        <div>
            <div class="inner"></div>
        </div>
    </div>
</div>

I can set up jQuery to select the outer and inner divs as such:

$outer = $('.outer');
$inner = $outer.find('.inner')

Works fine.

However, let's say I want to allow an unlimited nesting of this logic, so I may have this:

<div class="outer"> div a
    <div class="inner"> div b
        <div class="outer"> div c
            <div class="inner"> div d </div>
        </div>
    </div>
</div>

In that situation, when selecting div a via .outer I want to match it with only div b. In otherwords, I want to exclude ancestors of a nested .outer ancestor.

I'd like to have parings of outer and inner(s) contained within their nesting level.

I'm hoping .filter() could pull it off, but can't think of a selector that would work universally for unlimited nested patterns. Is it doable using a filter? Or maybe even a direct selector pattern?

UPDATE:

I think something like this could work, but not sure how one can (or if it's allowed) reference 'this' within a selector:

$outer = $('.outer');
$inner = $outer.not('this .outer').find('.inner')

UPDATE 2:

I should have mentioned this intially: .inner will always be a descendant of .outer but not necessarily an immediate child.

UPDATE 3:

Here's some test samples of HTML that could be used. In each case, I'd want to be able to select the .outer and pair up the .inner's it contains between itself and the nested outer. For clarity, I added names to each div (outer-x pairs with inner-x)

//sample 1
<div class="outer"> outer-a
    <div>
        <div class="inner"> inner-a
            <div class="outer"> inner-b
                <div class="inner"> inner-b </div>
            </div>
        </div>
    </div>
    <div>
        <div class="inner"> inner-a </div>
    </div>
</div>

//sample 2
<div class="outer"> outer-a
        <div class="inner"> inner-a
            <div class="outer"> inner-b
                <div>
                    <div class="inner"> inner-b </div>
                </div>
            </div>
        </div>
</div>

//sample 3
<div class="outer"> outer-a
        <div class="inner"> inner-a
            <div class="outer"> inner-b
                <div class="inner"> inner-b
                    <div class="outer"> outer-c 
                        <div class="inner"> inner-c</div>
                    </div>
                </div>
            </div>
        </div>
</div>

//bonus sample (we're trying to avoid this)
<div class="outer"> outer-a
        <div class="inner outer"> inner-a outer-b
            <div class="inner"> inner-b </div>
        </div>
</div>

UPDATE 4

I think I ended up going down a similar path as gnarf. I ended up with this:

var $outer = $('.outer');
var $inner = $outer.find('.inner').filter(function(){
    $(this).each(function(){
        return $(this).closest('.outer') == $outer; 
  });                                                                  
});

Am I on the right track there? It's not working so I assume I have a bit of a logic error still.

like image 661
DA. Avatar asked Jun 22 '10 18:06

DA.


1 Answers

Here's another option. Suppose you have the .outer o, this will select all inners under it:

o.find('.inner').not(o.find('.outer .inner'))

It should work identically to gnarf's answer, but a bit simpler.

First, it finds all inners under this outer.
Next, remove all inners that are descendants of other outers

Interactive working example: http://jsfiddle.net/Zb9gF/

Selector performance seems to be much better using this method as opposed to the .filter() as well: http://jsperf.com/selector-test-find-not

like image 141
Kobi Avatar answered Oct 21 '22 04:10

Kobi