I have a line of jQuery code which I don't understand.
var layerid = $('ul.layerstack li.selected').data('layerid');
I understand that $(ul.layerstack) is to select ul elements with layerstack class, and similarly for li.selected. But I don't understand the syntax for juxtaposing the two with a space in between.
Can someone please help explain this syntax and give a reference for this? (The DOM structure is listed below for reference).
Thanks,
It is called as the descendant selector... it is a part of css selector spec.
It is used to select all elements which satisfies the second selector which are inside the first part
Descendant selectors
A space means "any descendant of": direct children and children of those children would be selected.
I have following structure
<ul id="tabs" class="nav nav-tabs">
<li>AAA</li>
<li>BBB</li>
<li>CCC</li>
<li>DDD</li>
</ul>
Now I am operating on the anchor tag by following code and which is working fine.
$('#tabs a[href="#ddd"]').tab('show');
I am using pycharm which adds warning for the line by saying "Preface with ID selector". When I click it, pycharm changes to following
$('#tabs').find('a[href="#ddd"]').tab('show');
Both are working fine but I don't understand the difference.
What is the difference in both or more specifically what is difference between $('#tabs a[href="#ddd"]') and $('#tabs').find('a[href="#ddd"]')?
$("#tabs a") evaluates from right to left - which is the native direction of both Sizzle selector engine and querySelectorAll - i.e. first it finds all of the anchor elements in the page and then narrows it down to those under #tabs.
$("#tabs").find("a") evaluates - more intuitively - from left to right, i.e. first it finds #tabs, and then only the anchor elements under it.
Clearly the latter would yield better performance, but it would only be noticeable accumulatively; that is, if you run thousands of queries. Otherwise, the difference is negligible.
As stated in "Increase Specificity from Left to Right":
A little knowledge of jQuery’s selector engine is useful. It works
from the last selector first so, in older browsers, a query such as:
$("p#intro em");
loads every em element into an array. It then works up the parents of
each node and rejects those where p#intro cannot be found. The query
will be particularly inefficient if you have hundreds of em tags on
the page.
Depending on your document, the query can be optimized by retrieving
the best-qualified selector first. It can then be used as a starting
point for child selectors, e.g.
$("em", $("p#intro")); // or
$("p#intro").find("em");
But Test case says $("#tabs > a") would be fastest
The second one is MUCH quicker.
The reason being jQuery's selector enginge Sizzle, which traverses the selection from right to left, not vice versa.
This means that the selector
$('#tabs a[href="#ddd"]')
First queries the DOM document for a tag, which contains the attribute href set to #ddd. It then filteres out all of them, to get every one that is a <a> tag. At last, it traverses up the DOM tree for every node, trying to find a parent #tabs.
Imagine a site with 1.000 tags with href="#ddd", how tremendously slow that would be.
THEN.
The other variation pycharm suggest, is to first locate a element #tabs. This is super-quick, since jQuery can utilize the native browser method getElementById(). Having this node, it can traverse down to find all tags that are matching. By doing this, not all tags in the whole DOM-tree, needs to be checked. Only those which actually are in #tabs.
For further information, please check out this page in the documentation.
The effect is the same: Find anchors that have the value #ddd as href and are a descendant of #tabs. The difference lies in the way to achieve this.
The first solution finds the anchors and then checks if they are a descendant of #tabs.
The second solution finds #tabs and then finds the anchors. Which should be faster, of course.
.find() is better performance wise as compared to your first selector
$('#tabs a[href="#ddd"]').tab('show');
, that is why pycharm changes it to the selector using .find()
$('#tabs').find('a[href="#ddd"]').tab('show');
http://vaughnroyko.com/the-real-scoop-on-jquery-find-performance/
The difference is that find() allows you to filter on a set of elements based on a selection you've already made, returning and array of elements if that's the case.
$('#tabs').find('a[href=“#ddd”]');
And it's a more specific way of searching for an element because you are saying "hey, go to #tabs and find me all a[href=“#ddd”] in there" instead of you saying "hey, find me all this guys $('#tabs a[href=“#ddd”]') in all the code that i have."
While, in most cases, the performance is the only difference, the difference in approach can also affect the outcome of your code, depending on what selectors you are using.
For example, $("table").find("tr:even").addClass("even"); will add the "even" class to the every other row in each individual table that gets returned. So, if the "even" class makes the text in the rows bold and you have two tables, each with 3 rows, you would get the following result:
this is table one, row 1
this is table one, row 2
this is table one, row 3
this is table two, row 1
this is table two, row 2
this is table two, row 3
In both cases, the 1st and 3rd row of each table (i.e., the "even" rows . . . don't get me started on JQuery's even filter, selecting the odd rows . . .) are bolded.
On the other hand, $("table tr:even").addClass("even"); will add the "even" class to every other row in the entire group of rows from all tables combined.
this is table one, row 1
this is table one, row 2
this is table one, row 3
this is table two, row 1
this is table two, row 2
this is table two, row 3
In this situation, the the 1st and 3rd row of second table are actually the 4th and 6th rows of the entire group of <tr> elements, so they are treated as "odd". The 2nd row of the second table, however, is the 5th row of the entire collection and, thus, is treated as "even" and is bolded.
I have been able to select the specific rows that I wanted but I can't select specific td from those tr.
I used this to select rows:
$('#time-slot tr:not(:first, :last)')
then within those selected rows I was trying to ignore the first and the last td but it is not working. I used similar approach as above
$('#time-slot tr:not(:first, :last) td:not(:first, :last)')
Any ideas how should I approach this problem. Btw I am trying to click and drag the mouse to paint the cells with user defined color.
I prefer using less of a string selector and more of the jQuery methods, as well as using the :first-child and :last-child selectors for your problem:
$("#time-slot").find("tr").not(":first-child, :last-child").find("td").not(":first-child, :last-child").addClass("active");
http://jsfiddle.net/7b4Ms/
Depending on what you are expecting, which you haven't explained very well, this may or may not be what you want. What this does is select all tr elements that are not the first and last. Inside of those matched tr elements, it selects all td elements that are not first and last. So basically, it doesn't select the outside ring of cells in the table.
Totally agree with Ian, just I prefer to use .children() instead of .find(). Because it can make a problem if you have nested tables.
$("#time-slot").find("tr").not(":first-child, :last-child").find("td").not(":first-child, :last-child").addClass("active");
changes to:
$("#time-slot").children("tr").not(":first-child, :last-child").children("td").not(":first-child, :last-child").addClass("active");
Try this (uses css selectors only):
$("#time-slot tr:not(:first,:last) td:not(:first-child,:last-child)").addClass("active");
Sample
I have a table with some radiobuttons in it. When i click on a radiobutton, i want to update two of the sorrounding containers ID attribute (a div and a table). The problem is, i need to go 4 and 6 levels up, and the only way i know how to do this is parent().parent().parent().parent() etc.
I am looking for a better solution, and was hoping someone could point me in the right direction. You can see an image of how the "parent-child" tree is here:
http://imageshack.us/photo/my-images/834/imgkz.png/
I already have a clickhandler etc set up.
Basicly i need to check if the table's id attribute is "answeredTable", if not i need to change it. Also i need to check if the div two levels up from the table is "answered", if not, i need to change that too.
Thanks
You can use .closest('#answeredTable') or .parents('#answeredTable').
Using .parent() only selects the first parent element upon the DOM tree, selecting .closest() will allow you to walk up to DOM tree and match until it finds the element, while .parents() will return the whole parentset of the DOM and match the element in the whole parentset.
You need to use .parents() that go through multiple level of the DOM
For instance, in your example, you could get the surrounding div with this code:
$("#Q_18_2015").parents("div#answered")
By the way, id should be unique, or else, your code might probably not work. You should use classes instead.
<div class="answered">
Thus, the code would become:
$("#Q_18_2015").parents("div.answered")
provided that Q_18_2015 is really a unique id
I think what you want to use is closest http://api.jquery.com/closest/
you can use .parents
$("element").parent(".parentClass")
parents will go up the DOM until finds the parent with class parentClass
I am searching for a way how I could select a div element which is not the direct next one to the one which is "selected" by a click function.
<div id="click">(siblings)</div><div>text</div><div id="get this one"></div>
Now I would like to select the one with the id "get this one" - in my code this id is not available. All the divs have the same class and do have siblings.
I could select the third one by $(this).next().next() but I think it's not the best way to do it.
Also there can be divs before the one which is clicked - so it's not necessarily the first one.
I tried the :nth-child selector but didn't find a solution.
Later I also may want to select the 13th one after the click one (or the 23th, 65th and so on). This means I would like to have a rather dynamic solution to this problem.
Thanks for your help,
Phil
You can use .nextAll() with .eq() for your dynamic approach, like this:
$(this).nextAll().eq(1) //0 based index, this would be .next().next()
This would allow you to get n siblings forward, which seems to be what you're after.
It seems that $(this).parent().find('div').eq(2).attr('id') should work.
UPDATE( Added find('div') )