I'll just give a quick example to illustrate what I mean with the question. Say your HTML looks like this...
<div class="tabPanels">
<ul class="tabs clearfix">
<li>Tab1</li>
<li>Tab2</li>
<li>Tab3</li>
</ul>
</div>
How do I target the all the a tags in JavaScript? I understand that in jQuery you would do the following
$('.tabs li a').click(function(){
//jquery code here
});
How would I do the exact same thing with pure JavaScript?
Of course I could just do...
document.getElementsByTagName('a');
However suppose I have multiple li a tags in my webpage, I don't want to target all of them, only a specific set such as the ones above. Sorry if this is a dumb question. JQuery makes things easy, but I would like to do better with pure javaScript.
You have document.querySelectorAll function to do that: querySelectorAll
Note that is IE8+ function, but in this browser you only use it with CSS2 selectors.
Regards.
Related
Rather than use $('.list').find('li:not(.done):last'), which returns all LI that is not .done and is the last of every .list, how can I use functions instead?
For instance, $('.list').find('li').not('.done').last() would return just one item, because it searches all .list for LI that aren't .done and then just returns the last one.
There are a few reasons I want to do this. Primarily, typically using functions are faster than CSS selectors (in some cases, especially when you split them up into multiple functions as jQuery doesn't have to manually split up the selectors, and oftentimes jQuery functions are just mapped directly to existing CSS selectors anyway). But anyway, curiosity is my main reason at the moment, and performance is secondary.
Sample code (not entirely representative of the actual code, but the structure is similar):
<ul class="list">
<li>One</li>
<li class="done">Two</li>
</ul>
<ul class="list">
<li class="done">Three</li>
<li>Four</li>
</ul>
I want to return the nodes for:
One and Four.
I'm not coming up with a way to do it that doesn't require looping, e.g.:
$(".list").map(function() {
var items = $(this).find("li").not(".done");
return items[items.length - 1];
});
// Old way
$(".list").find("li:not(.done):last").css("color", "red");
// Just to show it's wrong (as the question says)
$(".list").find("li").not(".done").last().css("background-color", "yellow");
// Alternative
$(".list").map(function() {
var items = $(this).find("li").not(".done");
return items[items.length - 1];
}).css("border", "1px solid black");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="list">
<li>One</li>
<li>Two</li>
<li class="done">Three (done)</li>
</ul>
<ul class="list">
<li>One</li>
<li>Two</li>
<li class="done">Three (done)</li>
</ul>
The reason you might think using selectors is slower is that selectors like :last are jQuery extensions, not true CSS selectors, meaning that Sizzle (jQuery's selector engine) has to process them in JavaScript, rather than offloading them to the (much faster) selector engine built into the browser. If you restrict yourself to CSS selectors the browser implements, typically the selector will win (modulo other factors, and YMMV). I can't account for your seeming to see the DOM being changed by :not(.done) (which is a valid CSS selector), unless Sizzle does something It Really Shouldn't to process that (since Sizzle supports complex selectors within :not whereas CSS doesn't).
You don't actually need a function. Any of the following selectors would return the nodes for One and Four:
$('.list li:not(.done)')
$('.list li').not('.done')
$('li:not(.done)')
Using $('.list li:last-child').not('.done') would return those items that are both the last child and don't have a done class (Four).
That said, if you really want to use a function, you could go with jQuery's .contents() and .filter() methods.
$('.list').contents().filter( function(i,v){
if( v.nodeType === 1 && !$(v).hasClass('done') ){
return v; // Returns 'One' and 'Four'
}
});
Here's a fiddle of all of the above.
There are a few reasons I want to do this. Primarily, typically using functions are faster than CSS selectors
There are LIs that I don't want, and I want the last of every list that doesn't match a class
The fastest method would be XPath, since it is native:
//*[#class='list']/li[#class!='done']/*[last()]
But anyway, curiosity is my main reason at the moment, and performance is secondary.
jQuery 1.0 supported XPath, then switched to the selector engine which eventually became Sizzle:
Lately, I’ve been doing a lot of work building a parser for both XPath and CSS 3 – and I was amazed at just how similar they are, in some respects – but wholly different in others. For example, CSS is completely tuned to be used with HTML, with the use of #id (to get something by ID) and .class (to get something by its class). On the other hand, XPath has to ability to traverse back up the DOM tree with .. and test for existence with foo[bar] (foo has a bar element child). The biggest thing to realize is that CSS Selectors are, typically, very short – but woefully underpowered, when compared to XPath.
which were removed in 1.2:
Since XPath selectors were removed form jQuery in 1.2, a new XPath Selector Plugin has been introduced. You can use this plugin to give yourself the CSS/XPath hybrid selectors that have existed in jQuery since its creation.
DOM traversal techniques include:
Tree Walker
An implementation using the DOM Level 2 Tree Walker methods. Builds a generic filter function and traverses through all elements.
XPath
Building a single expression and letting the XPath engine traverse through the document, finding all the relevant elements.
Hybrid
Mixes an XPath and DOM implementation; using XPath wherever possible.
References
John Resig - XPath and CSS Selectors
John Resig - getElementsByClassName Speed Comparison
jQuery 1.2 Release Notes
jQuery XPath Plugin
I have some <li> elements, like this:
<ul class="some_class">
<li></li>
<li></li>
...
<li></li>
</ul>
And in my css file I have:
.some_class > li
I want to change some of that li elements by jQuery. My idea is to have something like this:
<ul class="some_class">
<div id="some_id">
<li></li>
<li></li>
</div>
...
<li></li>
</ul>
And change its by $("#some_id").html(). But its fails, because of css. I don't want to change css, cause its template css, and it's become very difficult to make changes in it.
Is there some other methods to perfom this?
Given the two pieces of source code you provided, your problem is not the CSS per say, but the way you changed the DOM, making the CSS invalid:
Solution 1:
Change:
.some_class > li
To:
.some_class li
Because in your code manipulation your <li></li> are now direct descendants of some_class your CSS is broken. In CSS > means direct descendant.
Solution 2:
If you don't want to change the CSS just add a class to the <li> you want to change, but do not nest them inside another div.
Note: given the comments about invalid HTML: Solution 2 will not cause a problem with your HTML, and for solution one, replace DIV for another UL
There are lots of ways to target elements, and especially with jQuery this is a breeze.
Of course you can just add a class to each of the elements you want to target, but there are lots of ways to do it without changing your markup at all. For example, you can select using the actual index of the element within the parent using eq(); use pseudo classes like first-child, last-child; use jQuery extensions like :even or :odd; use nth-child to select repeatable patterns like every third element (nth-child:(3n+3))...
I have the following HTML code:
<div id="mycontainer">
<p> title </p>
<ul>
<li><span>**</span>KEY</li>
</ul>
<ul>
...
</ul>
</div>
How would I get the KEY value? In other words, from this div with id = "mycontainer", how would I go to get from the first ul, the content of the element?
$("#mycontainer ul:first a").text();
here, have a fiddle: http://jsfiddle.net/8tvTt/
Something like this will achieve what you're after:
$("#mycontainer ul:first a").text();
This works:
$('#mycontainer ul:eq(0) a').text();
This works too: (more readable)
$('#mycontainer ul:first a').text();
Use this:
$('#mycontainer a').text();
While a lot of the existing answers will achieve what you're after, I think what you're really asking for (or at least what you really need) is some familiarity with jQuery selectors and DOM traversing.
A lot of people seem to be assuming that you want the inner text of the link element, which I am not sure is the case. Without providing for variations on this markup and without concern for speed of selectors, any number of answers will do what you want, including something as silly as $('a').text(); since its the only a in the markup you provided. And we can only guess about the circumstances. It'd be more helpful to understand how each of the answers works (and why the unsuccessful ones don't, for that matter) and why.
Specificity of selectors are desirable, but you have to weigh the costs and benefits of what can actually be costly trips through the DOM. Will you always be getting the text content of a link? Could it possibly ever contain html? Do you actually want to get the wrapping <a> as well?
If you just want the text content of the only a inside #mycontainer, sure:
$("#mycontainer ul:first a").text();
But $('#mycontainer').find('a').text(); might be faster. (Wait, what's find()?, you ask, and why is it faster?) But what if KEY is formatted <strong>ly, and you want that to carry over to whatever you're doing with it? You might want to use .html() instead. If you want the a itself, why not:
$("#mycontainer ul:first a");
But what if each li has an a?
$("#mycontainer ul:first li:first a").clone();
Do you want the span, too?
$("#mycontainer ul:first li:first").clone();
or
$("#mycontainer ul:first li:first").html();
Do you want the wrapping <li> as well?
$("#mycontainer ul:first li:first").clone();
Play around, read some more, and then you wont get everyone (myself included) so ravenous for a few silly, easy rep.
You need read jquery selectors... but use this
$('#mycontainer ul:first a').text();
Greetings,
I would like to toggle a huge multi-level ul with mootools 1.1 or plain javascript.
The list looks like:
HTML:
<ul>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
<li>
<ul>
<li>ddd
<ul>
<li>fff</li>
<li>ggg</li>
</ul>
</li>
<li>eee</li>
</ul>
</li>
</ul>
What I would like to do initially is to show the first level expanded, and the other levels collapsed and when each of the list items is clicked, to expand the ul below it.
Is it possible to do it without (greatly) modifying the html above?
From the documentation, I see that Fx.Slide is the most appropriate, however it accepts the id of the element as a parameter, which means I have to assign id's to each list item.
Is there a way by using selectors of collections of elements starting from the top?
I'm not sure whay I'll say apply with the very old 1.1 version. However, at least since 1.2, the element you need to pass is either the ID (like you said), either the actual element.
If you can use another version than 1.1, try the 1.3 which makes it easier to select the elements you want.
Here, I believe you need every <ul> element which has a direct <li> as parent. MooTools 1.3 features this new selector engine Slick, which would accomplish it fairly easilly: ul !> li.
However, I'm not sure (I didn't success) that the direct child selectors works properly with 1.1.
Here is what I came up with: http://jsfiddle.net/rCfwq/
Trying to select span within the first item in a usorted list but I can't quite seem to get the DOM right
<li class="chapterItem"> <a
href="http://www.neuromanga.com/mangaReader.php?chapterNo=12&#pageNo=1"
title="http://www.neuromanga.com/mangaReader.php?chapterNo=12&#pageNo=1
">Naruto 522 world</a> <span
id="date">Nov 21st 2010</span> <br>
<span style="display:none"
class="hiddenChapNo">12</span> </li>
Here is the jQuery code I been trying to use to select it
alert($('li').first().$('.hiddenChapNo').text());
You need to use .find() to get a descendant here, like this:
alert($('li').first().find('.hiddenChapNo').text());
Or a bit more compact with :first and a descendant selector (space):
alert($('li:first .hiddenChapNo').text());
Your code certainly looks like it should work, I assume that there's another <li> before this one that trips it up.
Also, ids are (should be) unique in a web page, so $('#hiddenChapNo') should be sufficient.
Assuming you need multiple hidden spans, the proper way to mark them would be <span class="hiddenChapNo"> (you can then also hide them with CSS instead of inline styles).
Try just using alert($('#hiddenChapNo').text());. An id should be unique on a page, use classes if you need otherwise.
Found a solution
alert($('.hiddenChapNo').first().text());