1

Suppose the following DOM structure:

.grandparent
  .parent
    .child .successful
      .a
      .b
        .an-arbitrary-subtree
  .parent
    .child
      .a
      .b
        .a-different-arbitrary-subtree
  .adopted
    .child
      .a
      .b
        .another-arbitrary-subtree
          .with-different-parents
            .but-sometimes-common-css-classes .successful

Were I to $('.grandparent').find('.successful') unsurprisingly, I'd get back [.child .successful, .but-sometimes-common-css-classes .successful]

Is there any way I might prevent jQuery's find method from traversing below the .child nodes? Perhaps I could reimplement $.find() myself and add a top-level class on the node to halt the search (in this case on .b)

Why am I asking? Even though we do not yet have Shadow Dom, I'd like to create components that can contain components (created by other developers anonymously) without worrying about leakages. Polymer isn't stable enough, yet. I prefer to scope my jQuery selectors in these components, but can only scope from the top node of a subtree, and have no means yet to constrain scope into the depths of the tree.

  • The example you give is a very simple one (that could just use a selector passed to children()). Is your aim to be able to specify an actual depth for the search search? – iCollect.it Ltd Jan 23 '15 at 22:27
  • 1
    Just edited my example to clarify, this question is meant to be applied to an arbitrary tree. I have a framework of nestable components, these components might be developed by different developers entirely who might use clashing class names. This obviously breaks for CSS without a shadow dom polyfill but how can I enforce selector scoping on the component subtree? – Michael Silveira Jan 23 '15 at 22:32
  • `enforce selector scoping on the component subtree` ... that is too broad for anyone to really address here. If it's a concern then write a spec for it and don't let it act like the wild west – charlietfl Jan 23 '15 at 22:40

5 Answers5

2

It's difficult to do this. If you want to have a reasonable guarantee of efficiency in the absence of additional information (e.g. when the subtrees you are not interested in could be arbitrarily large) then you would have to manually walk the DOM.

Otherwise, you could pull out all candidates and filter out those you don't want:

$('.grandparent')
    .find('.successful')
    .filter(function() { return !$(this).closest(".child").length; })

If you go the latter route make sure to be precise:

  • Do you want to filter out .child elements themselves if they are .successful? Using closest does this, but perhaps you need to not do so.
  • Is there a chance of a .child appearing above .grandparent? If so, the filter function needs to be buffed up so that it does not reject all candidate matches.
Jon
  • 428,835
  • 81
  • 738
  • 806
  • This is the closest to the answer. I'll need to ensure each subtree has an identifiable top-level-node and filter on those with different closest top-level-nodes than the one top-level-node of the element I'm performing a find on. – Michael Silveira Jan 23 '15 at 23:30
0

Can use not() method or :not() selector or filter(). Without some more realistic criteria to work from this example is a bit basic.

$('.grandparent .a').not('.adopted .child .a').doSomething();
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • Unfortunately, I as a parent might not always know my children. Nor my children's children. `not()` presumes this level of knowledge. – Michael Silveira Jan 23 '15 at 22:35
  • But without some more real world criteria it's hard to address your issue. Classes may not be what you need but perhaps tags ... I don't know what your higher level problem is – charlietfl Jan 23 '15 at 22:37
0

Consider using each(), then grabbing the first instance of .child from the returned list. Something like:

$('.parent').each(function() {
    return $(this).find('.successful').first();
});
isherwood
  • 58,414
  • 16
  • 114
  • 157
0

You could use .filter() and check for its parent element on each item of the collection.

0

If I understood you correctly, you want to reach all ".child" elements that have it's own ".success" child element. You can do this by searching for all ".success" child elements inside your ".grandparent" element , when you reach the ".success" element then search for its parent called ".child".

Something like this:

$('.grandparent').find('.successful').parents("child:first");

If this is not what you asked, hope it will help you finding right solution :)

Branimir Đurek
  • 632
  • 5
  • 13