2

I have a HTML structure that contains nested divs with the container class:

<div class="container" id="0">
  <div id="1">
    <div class="container" id="2">
      <div class="container" id="3"></div>
    </div>
    <div id="4">
      <div class="container" id="5"></div>
    </div>
  </div>
</div>

This could include more divs and deeper/different nesting.

Starting from some point in the tree I'd like to find all containers in that subtree that are not nested within other containers. So for example from div #1 I'd like to find the divs #2 and #5, but not #3 (since it is nested in container #2 already found).

What would be the best way to accomplish this?

sth
  • 222,467
  • 53
  • 283
  • 367
  • Numeric IDs are invalid. That said, is there a reason why you wouldn't just select them by their ID? Or do they not actually have IDs? – user113716 Jan 18 '11 at 19:20
  • @patrick: I only put the ids there to make it easier to talk about the different divs, they are not actually there in the real code. – sth Jan 18 '11 at 19:25
  • I see. Will the ones you want to exclude always be a *direct* child of another `.container`? Or could there be some non `.container` separating them? – user113716 Jan 18 '11 at 19:34
  • Also, since you don't have IDs, how are you selecting `#1`? Or should its selection be part of the solution? It makes a bit of a difference if using a selector-based solution. – user113716 Jan 18 '11 at 19:52
  • @patrick: In general the ones I want to exclude are **not** necessarily a direct child of another `container`. There could be other nodes separating them. The "base node" `#1` would already be selected by other means, for example by a global id or by some previous selection done in the outer `#0` container. – sth Jan 18 '11 at 20:29

3 Answers3

2

Try using jQuery's filter() method:

$items = $('#0').find('.container').filter(function(index) {
    return !$(this).parents(':not(#0)').hasClass('container');
});

Basically, it finds all items with class .container below your top .container and filters the set based on whether or not the direct parent has the class .container.

See here for a working example: http://jsfiddle.net/TzL8Z/1

treeface
  • 13,270
  • 4
  • 51
  • 57
  • although that doesnt work if the nesting isnt 1 level down, e.g. http://jsfiddle.net/r8nED/ all i changed was i made id=3 1 level further down in the markup. the OP said he doesn't want id=3 selected, but your algorithm selects it - you need to use `parents()` not `parent()` which should make my solution faster – davin Jan 18 '11 at 19:31
  • @davin: Thanks for the heads up, though your solution isn't entirely correct either. You need to use `parents(':not(#0)')` or else it returns no set because the outer container has the class `container`. I've updated my answer. – treeface Jan 18 '11 at 20:05
  • i dont see where my solution returns no set when the expected output is not empty.. now that you use `parents()` your solution doesnt solve the original problem because you're looking up the tree too far: http://jsfiddle.net/TzL8Z/3/ – davin Jan 18 '11 at 20:34
  • 1
    i didnt intend on ambushing you. im not normally a prick, please dont take it personally. – davin Jan 18 '11 at 20:35
2
function getOuterContainers(el) {

    if (el.length == 0)
        return $([]);
    else
        return el.children('.container').add( getOuterContainers(el.children(':not(.container)')) );

}

check it out: http://jsfiddle.net/GZ3Tx/

davin
  • 44,863
  • 9
  • 78
  • 78
0

A solution working with arbitrary starting nodes:

function getContainers(base) {
   return base.find('.container').not(base.find('.container .container'));
}

Example: http://jsfiddle.net/tejp/GSRH2/2/

The advantage is that this works with an arbitrary starting node that doesn't need to be selectable with a simple JQuery selector, like it is the case in some of the other answers. Also it doesn't require "manually" walking over the whole tree with children().

The approach can also be easily extended to similar problems, like for example getting all .items not nested into a .container.

sth
  • 222,467
  • 53
  • 283
  • 367