What would be the vanilla JS equivalent of :has in this jQuery selector?
$('.main-container').children('.analytics:has(a)').not('#promo')
Within .main-container
, I'm trying to select all .analytics
elements without an id of "promo" that contain <a>
tags.
What I've tried:
document.querySelectorAll('.main-container .analytics:not(#promo)')
This will give me close to what I want, but I still have to filter out those .analytics
parents that do NOT have <a>
tags.
What would be the best way to approach this using vanilla JS?
You can use the function getElementsByTagName() which queries the DOM for elements of a certain tag and returns a collection of elements.
Vanilla JS helped the developers in creating dynamic websites. Then came jQuery, a library of tools created by developers around the world, using Javascript. In simple words, jQuery is a lightweight and easy to use JavaScript library that helps in creating complex functionalities with few lines of coding.
In jQuery, you can listen to events for dynamically added elements using the on() function. The equivalent in JavaScript is addEventListener() function.
.analytics:not(#promo)
element => element.querySelector('your-selector')
element.querySelector('your-selector')
will evaluate tonull
(which is falsey) if no child element is found
function has(nodeList, selector) {
return Array.from(nodeList).filter(e => e.querySelector(selector))
}
const nodeList = document.querySelectorAll('.main-container > .analytics:not(#promo)')
has(nodeList, 'a').forEach(e => e.style.background = "red")
<div class="main-container">
<div class="analytics">
<a>Should be red</a>
</div>
<div class="analytics">
Should not be red
</div>
<div id="promo" class="analytics">
<a>Should not be red</a>
</div>
</div>
NodeList.prototype.has = function(selector) {
return Array.from(this).filter(e => e.querySelector(selector))
}
document
.querySelectorAll('.main-container > .analytics:not(#promo)')
.has('a')
.forEach(e => e.style.background = 'red')
<div class="main-container">
<div class="analytics">
<a>Should be red</a>
</div>
<div class="analytics">
Should not be red
</div>
<div id="promo" class="analytics">
<a>Should not be red</a>
</div>
</div>
You could select the <a>
and then get their parentNodes:
var a = document.querySelectorAll('.main-container .analytics:not(#promo) a');
var yourElements = [];
for (var i = 0; i < a.length; i++) {
yourElements.push(a[i].parentNode);
}
yourElements.forEach(e => e.style.background = "red");
<div class="main-container">
<div class="analytics">
<a>Should be red</a>
</div>
<div class="analytics">
Should not be red
</div>
<div id="promo" class="analytics">
<a>Schould not be red</a>
</div>
</div>
EDIT: just noticed this only works if the <a>
is a direct child of your wanted element.
There is no equivalent selector for :has
, you'll have to use an initial selection and then filter them
var el = document.querySelectorAll('.main-container > .analytics:not(#promo)');
var res = [];
for (let x = 0; x < el.length; x++){
if (el[x].querySelector('a')) res.push(el[x]);
}
//res has has the array of elements needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With