Select elements whose children don't contain specific elements in jQuery - javascript

I want to select all divs on a page whose children don't contain an element with a specific class.
I can select elements whose descendants do contain the class with:
$('div').has('.myClass');
So I just want the inverse of this.

I'd use ".filter()":
var theDivs = $('div').filter(function() {
return $(this).find('.myclass').length === 0;
});

A simple $("div:not(:has(.myClass))") will do the job.
How it works internally in jQuery?
1) $("div") - gets all DIVs from the document.
2) :not(:has(.myClass)) - These are two statements one nested in another. Now jQuery executes :has(.myClass) on resulted DIVs in above step and gets all DIVs with class name 'myClass'
3) :not() - This pseudo-selector method will be applied on All DIVs from Step 1 against the DIVs resulted from second statement to find DIVs without '.myClass'. This is possible by looping through all DIVs from Step 1 and comparing DIVs from second step.

$('div:not(:has(*>.myClass))');

$('div').has(':not(.myClass)');

Related

JavaScript: Add a class specific tag in classList

I have a class named X which has multiple <span> inside and I also have a css selector X span.
In JavaScript how can I use X span instead of X in the following case:
document.querySelector('.ABC').classList.add(X)
I tried document.querySelector('.ABC').classList.add(X span) which definitely isn't working.
In Javascript, working with the HTML works like this:
You ask the browser to give you an object or list of objects that correspond to the HTML elements
You use the objects to modify the page
If I understand correctly, what you want to do is:
Find element by className ".ABC"
Find "span"-s inside that element
Give those spans a class
To do those, follow these steps:
// get the first element that matches .ABC
let parent = document.querySelector(".ABC");
// now parent is either an Element, or undefined/null
// if it's not null, we can call querySelectorAll
// get all elements inside the parent that are spans
let spans = parent.querySelectorAll("span");
// spans is now either an array of Elements, or undefined/null
// if it's not null, we can iterate over it
for (let span of spans) {
span.classList.add('X');
}

jQuery counter and adding a class but not to the first two?

I'm checking list items I have and if there are more than two then I add a class. This works fine but I want the class to start adding after the first two list items. I am not sure how to do that part that excludes adding the class to the first two. Here is my code:
$(document).ready(function() {
//Checking how many time the class appears
var numItems = $('ul.singleMagazine li').length;
if (numItems > 2) {
alert(numItems);
//Want to add this class but not to the first two - exclude first two list items and then add it to the rest. How to do it?
$('ul.singleMagazine li').addClass("newClass");
}
});
How I would do the excluding part?
The li elements should be siblings, so you can use the gt() selector:
$('ul.singleMagazine li:gt(1)').addClass("newClass");
Also note that the length check is redundant as if there's less than two items the above won't do anything anyway.
You can use gt selector. https://api.jquery.com/gt-selector/
$('ul.singleMagazine li:gt(1)').addClass("newClass");
This will add the class only to the li's which are greater than 1. Note here that the indexing starts from 0.

jQuery select all classes except one ID

I need to select all divs of a certain class (jqx-slider) excluding one ID (#str_prg) - something like:
$("div.jqx-slider :not(#str_prg)").each(function () {
.....
});
What is the correct syntax for that?
Also, would it be faster and more effecient code, if I add a "if" condition inside the loop - like
if($(this).attr('id') ! = "str_prg"){
}
Thanks!
You are using an descendant selector between the class selector and the not selector, which is invalid for your requirement
$("div.jqx-slider:not(#str_prg)")
when you say $("div.jqx-slider :not(#str_prg)") it selects all descendants of elements with class jq-slider except the one with id str_prg
Try to remove an unnecessary space char like this:
$("div.jqx-slider:not(#str_prg)")
Remove the space, as it would cause you to select children, instead of the element itself.
$("div.jqx-slider:not(#str_prg)").each(function() {
.....
});
For the second part of your question, it would be better to just use the CSS selector instead of a JS loop.

jQuery .index() strangeness

I'm by no means a jQuery (or JavaScript) expert so forgive me if I'm misunderstanding or overlooking something. I have the following HTML:
<html>
<body>
<div class="ted">Ted</div>
<div class="ted">Ted</div>
<div class="tim">Tim</div>
<div class="ted">Ted</div>
<div class="tim">Tim</div>
</body>
</html>
And the following JS:
$('.ted').click(function() {
alert($(this).index());
});
When I click a div with the class '.ted' the alert should show the index of that div.
Clicking the first div alerts '0' (expected), the second div alerts '1' (expected). However, clicking the last '.ted' div (the fourth in the list) alerts '3' - why is this not giving an index of 2? (as JS arrays are 0 based) and this is the third '.ted' div?
It's as if $('.ted') is actually bringing back all the divs in the list?
Example here: http://jsfiddle.net/nha2f/6/
The .index() method docs make this behaviour clear. Here's the relevant part (emphasis added):
If no argument is passed to the .index() method, the return value is an integer indicating the position of the first element within the jQuery object relative to its sibling elements.
Since the third element that matches your selector is actually the fourth child of its parent, it has an index of 3.
Continue reading through the documentation to find the solution to your problem:
If a selector string is passed as an argument, .index() returns an integer indicating the position of the original element relative to the elements matched by the selector.
So, you can pass the same selector to .index() and it will return the index of the element relative to the matched set:
alert($(this).index(".ted"));
.index() returns the index of the clicked element in it's parent, relative to it's siblings. Not compared to other divs with the same event listeners / class / id. Your third '.ted' div is the fourth child of your body.
To get the behavior you want, add a selector to your index call: Fiddle
$('.ted').click(function() {
alert($(this).index(".ted"));
});
When you pass a selector into index, it tells jQuery to look for the element in that set. If you don't, it looks to see where it is relative to all of its sibling elements.
Or alternately, remember the list of ted elements and then invert things: Fiddle
var teds = $(".ted");
teds.click(function() {
alert(teds.index(this));
});
When you pass an element into index, that tells jQuery to look for that element in the set.
the index is the child within the parent. If you want to enumerate the .ted elements try this:
$('.ted').each( function( i, a ){
$(a).click( function(){
alert( i ); // <- should be 0, 1 or 2.
} );
} );

How to use jQuery to remove divs containing specific text, as well as the HR divider after only the divs removed

On a page that contains a list of <div> blocks, each of which contain location info, and after each <div> there is an <hr>, I need to target and remove all divs that do not have the city Boston in them.
I was able to easily remove those divs with:
$("div.location").not(":contains('Boston')").remove();
That was when I noticed the surplus of leftover <hr>
Would it be better to target and remove all of the dividers first? Then the divs? Can I do both with one stroke of jQuery? Thanks!
$("div.location").not(":contains('Boston')").next('hr').remove().end().remove();​
DEMO
NOTE to comment
$("div.location").not(":contains('Boston')") // return the target div
.next('hr') // take the pointer to hr, next to target div
.remove() // remove the hr
.end() // return the pointer to target div.location again
.remove();​ // remove the target div
Can I do both with one stroke of jQuery
Not that it's any "better", but you can always just chain it, remove the next() HR, then use end() to step back and remove() the div, or do it the other way around removing the div first, does'nt really matter much:
$('div.location').filter(function() {
return $(this).text().indexOf('Boston') == -1;
}).next('hr').remove().end().remove();
The obvious one is $("div.location:not(:contains('Boston')), div.location:not(:contains('Boston')) + hr").remove()​
Use a simple selector, then get the conjunctive hr elements left over
$("div.location:not(:contains('Boston'))").remove().add("hr+hr").remove();
EDIT:
alternate avoid double dom manipulation by direct selection first
$("div.location:not(:contains('how'))").add("div.location:not(:contains('how'))+hr").remove();

Categories