Reputation: 657
This as part of CSS selector learning I came across this problem. I am trying to select an element based on the existence of a sibling element. So If I have to quote an example,
<div class = "parentDiv">
<div class = "abc">
<span>Note</span>
</div>
<div class = "abd">
<span><a>testLink</a></span>
</div>
</div>
<div class = "parentDiv">
<div class = "abc">
<span>Note2</span>
</div>
<div class = "abd">
<span>te</span>
</div>
</div>
For the above example, I am trying to select all span elements inside class .abc
if its sibling .abd
has an a
tag
What I tried is document.querySelectorAll('.parentDiv > .abc span ~ .abd span a');
which doesnt seem to work.. any idea what I could be doing wrong
Upvotes: 2
Views: 237
Reputation: 7819
This cannot be done with CSS selectors alone (yet).
The ~
selector selects elements on the same level in the DOM tree. Your a
element isn't a direct sibling to your span
, which is why your selector fails to return any results.
//What you'll want to do, is first select all instances of links:
var links = document.querySelectorAll('.parentDiv > .abd span a');
//Let's also create an empty array for matches:
var s = [];
//Then iterate over our matches:
Array.prototype.forEach.call(links, findSiblings);
function findSiblings(link){
//Here, we can traverse back up to .parentDiv:
var parent = link.parentElement.parentElement.parentElement;
//Now, we have a only '.parentDiv's that contain '>.abd span a'.
//Let's run another query on that element to find any spans contained in '.abc':
var spans = parent.querySelectorAll('.abc span');
//Now, we have a new collection. Let's push each to our array:
Array.prototype.forEach.call(spans, function(element){
s.push(element)
});
}
//Now, we have all the matches in our s-array:
alert(s.length);
Demo + a more compact version of the code: https://jsfiddle.net/p6nz011p/6/
Or, if you're using jQuery, you could simply do:
var s = $('.parentDiv:has(>.abd span a) >.abc span');
alert(s.length);
Note, that once browsers have support for the CSS Selectors Level 4 :has()
selector, you may use this selector without jQuery in querySelectorAll()
, too.
Upvotes: 1
Reputation: 8885
Update
It is an alternative using pure JavaScript:
var selectors = document.querySelectorAll('.abd span a');
if (selectors) {
selectors.forEach(function(selector) {
selector.style.backgroundColor = 'yellow';
selector = selector.parentNode.parentNode.parentNode;
elements = selector.querySelectorAll('.abc span');
if (elements) {
elements.forEach(function(element) {
element.style.backgroundColor = 'red';
});
console.log('.abc span: ' + elements.length);
}
});
console.log('.abd span a: ' + selectors.length);
}
<div class="parentDiv">
<div class="abc">
<span>Class> abc, tag> span: 1.0</span><br>
<div>Class> abc, tag> div: 1.0</div>
<span>Class> abc, tag> span: 1.1</span><br>
<span>Class> abc, tag> span: 1.2</span><br>
<div>Class> abc, tag> div: 1.1</div>
<div>Class> abc, tag> div: 1.2</div>
</div>
<div class="abd">
<span><a>Class> abd, tag> span a : 1.0 </a></span>
</div>
</div>
<div class="parentDiv">
<div class="abc">
<span>Class> abc, tag> span: 2.0</span><br>
<span>Class> abc, tag> span: 2.1</span><br>
<span>Class> abc, tag> span: 1.2</span><br>
</div>
<div class="abd">
<span>class> abd, tag> span: 2.0</span>
</div>
<div class="parentDiv">
<div class="abc">
<span>Class> abc: 3.0</span>
</div>
<div class="abd">
<span><a>Class> abd, tag> span a : 3.0</a></span>
</div>
</div>
<div class="parentDiv">
<div class="abc">
<span>Class> abc, tag> span: 4.0</span>
</div>
<div class="abd">
<span>Class> abd, tag> span: 4.0</span>
</div>
<div class="abc">
<span>Class> abc, tag> span: 4.1</span><br>
<span>Class> abc, tag> span: 4.2</span><br>
<span>Class> abc, tag> span: 4.3</span><br>
</div>
</div>
Upvotes: 1
Reputation: 3787
The tilde combinator selects only if the operands are childrens of the same parent. They must be at the same level. MDN reference.
Upvotes: 0