Exclusive CSS selector - javascript

I am working on a page where the selected item among a list is characterized by NOT having a given class. Something like the following:
<ul>
<li class="a">not selected</li>
<li class="a b">selected</li>
<li class="a">not selected</li>
</ul>
I would like to defined a CSS selector to grab the li node in the page having ONLY the a class.
Unsurprisingly the following statement is not enough:
document.querySelectorAll('li.a')
Because it returns ALL the li nodes having the a class.
Any experience on such scenario?

In such case you may consider attribute selector like this:
console.log(document.querySelectorAll('li[class="a"]').length)
li[class="a"] {
color:red;
}
<ul>
<li class="a">Select me</li>
<li class="a b c d more classes">Don't select me</li>
<li class="a b">Don't select me</li>
<li class="a">Select me</li>
</ul>
Simply pay attention to extra spaces:
console.log(document.querySelectorAll('li[class="a"]').length)
li[class="a"] {
color:red;
}
<ul>
<li class="a ">Pay attention to this one !!</li>
<li class="a b">Don't select me</li>
<li class="a">Select me</li>
</ul>
But since you are using JS you can use trim() to get rid of the extra spaces:
var elem=document.querySelectorAll('li');
for(var i=0;i<elem.length;i++)
elem[i].className=elem[i].className.trim();
console.log(document.querySelectorAll('li[class="a"]').length)
li[class="a"] {
color:red;
}
<ul>
<li class="a ">Pay attention to this one !!</li>
<li class="a b">Don't select me</li>
<li class="a">Select me</li>
</ul>

Apart from Temanis answer you can use the not selector in this case
document.querySelectorAll('li.a:not(.b)')

You can use the :not() pseudo, that's exactly what you need for this job.
https://developer.mozilla.org/en-US/docs/Web/CSS/:not
So all you have to do is
document.querySelector(".a:not(.b)")
But also consider using jQuery, like
$(".someclass").not(".another")
Stansard querySelector is faster, jQ is more readable.

Related

Navigating the DOM: selecting ul childrens

Let's say that I have a nested <ul> that looks like this:
<ul>
<ul class="pizzatype">
<h1>Margherita</h1>
<li class="ingredient">Tomato sauce</li>
<li class="ingredient">Mozzarella</li>
<li class="ingredient">Origano</li>
</ul>
<ul class="pizzatype">
<h1>Spicy salamino</h1>
<li class="ingredient">Tomato sauce</li>
<li class="ingredient">Mozzarella</li>
<li class="ingredient">Salamino</li>
</ul>
<ul class="pizzatype">
<h1>Onion n' Tuna</h1>
<li class="ingredient">Tomato sauce</li>
<li class="ingredient">Mozzarella</li>
<li class="ingredient">Tuna</li>
<li class="ingredient">Onion</li>
</ul>
</ul>
And a script that console.log the childrens of class "pizzatype":
var pizzatype = document.querySelectorAll('.pizzatype');
console.log(pizzatype[1].children[3]);
The console.log at children[3] returns: <li class="ingredient">Salamino</li>
But I'm looking for a parameter that returns just Salamino
Anyone can help?
Also, is there any reference site that I can consult to find out which parameters can be asked, starting from the children function? Like children.text, children.value etc
Use textContent to get the text of an element
console.log(pizzatype[1].children[3].textContent);
What you're currently doing is pointing to the li element it's self. You need to target the text of this element.
You can do this by using .innerText. You can also use .innerHTML, which will return the text in raw format and won't automatically encode/decode text.
console.log(pizzatype[1].children[3].innerHTML);

Selector in jQuery working in an unintuitive way

I have a selector as follows.
subMenus.children("li.tab").children("a").each(function () { ... }
It works as supposed to. Then, I read on the website that the following is also supposed to work (and since it's more compact, I prefer it that way).
subMenus.children("li.tab>a").each(function () { ... }
However, the latter seems not to find any elements as the action in the squiglies doesn't execute. What am I missing?
Edit
Markup as requested.
<ul id="submenu1" class="tabs tabs-transparent">
<li class="tab">A</li>
<li class="tab">B</li>
</ul>
<ul id="submenu2" class="tabs tabs-transparent">
<li class="tab">A</li>
<li class="tab">B</li>
</ul>
<ul id="submenu3" class="tabs tabs-transparent">
<li class="tab">A</li>
<li class="tab">B</li>
</ul>
A child combinator in CSS is the "greater than" symbol, it looks like this:
ol > li {
color: red;
}
It means "select elements that are direct descendants only". In this case: "select list items that are direct descendants of an ordered list". To illustrate:
<ol>
<li>WILL be selected</li>
<li>WILL be selected</li>
<ul>
<li>Will NOT be selected</li>
<li>Will NOT be selected</li>
</ul>
<li>WILL be selected</li>
</ol>
Try removing the > symbol.
$("li.tab a");
The first jQuery selector is looking for children of your <li/> (including grandchildren).
$("li.tab").children("a");
Whereas your second jQuery selector is looking for direct children of your <li/> (NOT including grandchildren).
$("li.tab > a");
Update:
You'll want to use .find instead of .children because
The .children() method differs from .find() in that .children() only
travels a single level down the DOM tree while .find() can traverse
down multiple levels to select descendant elements (grandchildren,
etc.) as well.
Source: https://api.jquery.com/children/
Try find().
Technically "li.tab > a" is not a "child" of subMenus
$(".tabs").find("li.tab>a").each(function () { console.log(this); });
<ul id="submenu1" class="tabs tabs-transparent">
<li class="tab">A</li>
<li class="tab">B</li>
</ul>
<ul id="submenu2" class="tabs tabs-transparent">
<li class="tab">A</li>
<li class="tab">B</li>
</ul>
<ul id="submenu3" class="tabs tabs-transparent">
<li class="tab">A</li>
<li class="tab">B</li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
.children() would only select direct children. So subMenus.children("li.tab>a") would select anchor tags that are direct children of subMenus, and also direct children of li.tab.
Here you can use .find() instead: subMenus.find(">li.tab>a").each()
Try this
subMenus.children("li.tab>a").each(function () { ... }

Slide up multiple <ul> elements using jQuery

I am trying to construct a jquery statement that will slideUp() all <ul> elements whose siblings don't contain a set of specific classes (.clicked, .chosen).
Suppose I have the following nested <ul> structure:
<ul class="mainmenu">
<li>Dogs</li>
<ul>
<li>Fido</li>
<li class="chosen">Barney</li>
<li>Turbo</li>
</ul>
<li>Cats</li>
<ul>
<li>Sylvester</li>
<li>Felix</li>
<li>Garfield</li>
</ul>
<li class="clicked">Hamsters</li>
<ul>
<li>Chubbs</li>
<li>Oreo</li>
<li>Ruby</li>
</ul>
</ul>
For the above example, I would like to slideUp() only the 'Cats' <ul> element ('Sylvester', 'Felix', 'Garfield') because none of it's elements use the 'chosen' or 'clicked' classes.
My current jquery statement reads:
$('.mainmenu').first().siblings().not('.clicked, .chosen').slideUp();
This, and everything else I have tried, returns nothing. Suggestions?
You HTML looks challenging :) but somehow, I've managed to create a query to perform what you're looking for.
And if you want to check multiple class for particular element you can use is() as well.
//Check li doesn't have clicked class and then filter ul next to the li
$('.mainmenu > li').not('.clicked').next('ul').filter(function(){
//Find the ul, if it's any of li doesn't have chosen class
if(!$(this).find('li').hasClass('chosen'))
{
return $(this);
}
}).slideUp();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="mainmenu">
<li>Dogs</li>
<ul>
<li>Fido</li>
<li class="chosen">Barney</li>
<li>Turbo</li>
</ul>
<li>Cats</li>
<ul>
<li>Sylvester</li>
<li>Felix</li>
<li>Garfield</li>
</ul>
<li class="clicked">Hamsters</li>
<ul>
<li>Chubbs</li>
<li>Oreo</li>
<li>Ruby</li>
</ul>
</ul>

Jquery: select an element when two or more conditions are true

I have an element like this
<ul>
<li data-ud="321" data-id="42">
<li data-ud="322" data-id="42">
<li data-ud="323" data-id="42">
<li data-ud="324" data-id="42">
<li data-ud="321" data-id="43">
<li data-ud="322" data-id="43">
<li data-ud="323" data-id="43">
<li data-ud="324" data-id="43">
<li data-ud="321" data-id="44">
<li data-ud="322" data-id="44">
<li data-ud="323" data-id="44">
<li data-ud="324" data-id="44">
<li data-ud="321" data-id="45">
<li data-ud="322" data-id="45">
<li data-ud="323" data-id="45">
<li data-ud="324" data-id="45">
</ul>
Now I want to select a element with data-id=45 and data-ud=322. I have tried but it didn't work.
Thanks in advance
To use 'and' in a selector, simply don't use any other separator, eg a li and class myclass would be:
li.myclass
to find by attribute, use [attribute=x], so to combine the two:
li[data-id=45][data-ud=322]
or, with jquery:
$("li[data-id=45][data-ud=322]")
This can be difficult to read and prone to errors eg a space between the two [][] will give a totally different result, so you can instead use filter to the same effect:
$("li").filter("[data-id=45]").filter("[data-ud=322]")
Fiddle example: https://jsfiddle.net/o9fdhphf/
Try the following:
$('li[data-id=45][data-ud=322 ]');
$("[data-ud=322][data-id=45]").text()
OR
$("[data-ud=321] + [data-id=45]").text()
JSFiddle

cloning only a specific item in a list using .clone() in Jquery

I am trying to add only select items of a list to a new list. So for example, I only wish to add banana to my second list, the following code in my function adds all the items in coll-selected-list to coll-grouped-list. How may I only make a clone of a specific item. Any tips would be great.
jQuery:
$("#coll-selected-list li").clone().appendTo("#coll-grouped-list");
Markup:
<ul id="coll-selected-list" class="droptrue sort-drop ui-sortable">
<li class="sorted">apple</li>
<li class="sorted">pear</li>
<li class="sorted">banana</li>
<li class="sorted">grape</li>
<li class="sorted">guava</li>
</ul>
<ul id="coll-grouped-list">
</ul>
You can use the :contains selector:
$("#coll-selected-list li:contains('banana')").clone().appendTo("#coll-grouped-list");
Note that the string you pass to :contains is case sensitive.
Here's a working example.
Add a custom data attribute and value to the items you want to clone and then only target items with that data attribute and value.
e.g.
<ul id="coll-selected-list" class="droptrue sort-drop ui-sortable">
<li class="sorted">apple</li>
<li class="sorted">pear</li>
<li class="sorted" data-action="clone">banana</li>
<li class="sorted">grape</li>
<li class="sorted">guava</li>
</ul>
<ul id="coll-grouped-list">
</ul>
$('#coll-selected-list li[data-action="clone"]').clone().appendTo("#coll-grouped-list");
Working Demo:
http://jsfiddle.net/QXEdn/
You can add class to elements which you want to clone e.g.:
<ul id="coll-selected-list" class="droptrue sort-drop ui-sortable">
<li class="sorted">apple</li>
<li class="sorted">pear</li>
<li class="sorted clone">banana</li>
<li class="sorted">grape</li>
<li class="sorted">guava</li>
</ul>
<ul id="coll-grouped-list">
</ul>
// get elements with clone class
$('#coll-selected-list li.clone]').clone().appendTo("#coll-grouped-list");
If you want to clone elements based on index you can use :eq selector:
// clone li containing bannana
$('#coll-selected-list li:eq(2)]').clone().appendTo("#coll-grouped-list");

Categories

Resources