Reputation: 54618
I want to be able to select an element and find all descendant elements with a specific class but are not contained with a similar parent element. It's hard to describe:
Html:
<div class="js-test js-1">
<div class="b">1</div>
<div class="b">1</div>
<div class="d">
<div class="b">1</div>
</div>
<div class="js-test js-2">
<div class="b">2</div>
<div class="b">2</div>
<div class="b">2</div>
<div class="d">
<div class="b">2</div>
</div>
<div class="js-test js-3">
<div class="b">3</div>
<div class="b">3</div>
<div class="b">3</div>
<div class="b">3</div>
<div class="d">
<div class="b">3</div>
</div>
</div>
</div>
</div>
Attempted jQuery:
$(document).ready(function(){
function test(element)
{
var test2 = element.find('.b :not(.js-test .b)');
console.log(test2.length);
}
console.clear();
test($('.js-1'));
test($('.js-2'));
test($('.js-3'));
});
Expected Results:
3
4
5
Actual Results:
0
0
0
Upvotes: 1
Views: 359
Reputation: 54618
I ended up using something similiar to billyonecan's answer:
$(document).ready(function(){
function test(element)
{
var all = element.find('.b');
var exclude = element.find('.js-test .b');
var test = all.not(exclude);
console.log(test.length);
}
console.clear();
test($('.js-1'));
test($('.js-2'));
test($('.js-3'));
});
Actual Results:
3
4
5
The intended application's result set is so small that I don't believe there is any significant different in performance between any solution here.
Upvotes: 0
Reputation: 1
Try
// descendant `.b` of `element`,
// descendant `.b` of `element`, not `.b`, not `.js-test`
var test2 = element.find("> .b, > :not(.b):not(.js-test) .b");
jsfiddle http://jsfiddle.net/ku2pdn2j/4/
$(document).ready(function(){
function test(element) {
var test2 = element.find("> .b, > :not(.b):not(.js-test) .b");
console.log(test2.length, test2);
}
console.clear();
test($('.js-1'));
test($('.js-2'));
test($('.js-3'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div class="js-test js-1">
<div class="b">1</div>
<div class="b">1</div>
<div class="d">
<div class="b">1</div>
</div>
<div class="js-test js-2">
<div class="b">2</div>
<div class="b">2</div>
<div class="b">2</div>
<div class="d">
<div class="b">2</div>
</div>
<div class="js-test js-3">
<div class="b">3</div>
<div class="b">3</div>
<div class="b">3</div>
<div class="b">3</div>
<div class="d">
<div class="b">3</div>
</div>
</div>
</div>
</div>
Upvotes: 0
Reputation: 723448
The selector .b :not(.js-test .b)
finds descendants of .b
elements that are not .js-test .b
elements. The problem with this selector is twofold:
Every .b
element is a descendant of a .js-test
element. This includes the .b
elements immediately nested within each context .js-test
element that you are testing.
The space between the first .b
and the :not()
represents a descendant selector, which also means that the element being represented by :not()
could very well be a :not(.b)
entirely and still match.
But none of your .b
elements have any element descendants, and this is the real reason why all of your test results are zero.
Since you can't directly create a selector corresponding to the context element (the argument element
), you will need to write a custom filter function like the one proposed by billyonecan, and filter according to whether its closest .js-test
ancestor is the context element.
Upvotes: 1
Reputation: 20250
You'd have to do some filtering to only count occurrences of .b
where the closest .js-test
equals element
:
element.find('.b').filter(function() {
return $(this).closest('.js-test').is(element);
}).length;
Upvotes: 1