I have this little code:
$("ul#mainnav > li").hover(function(){
$("ul#mainnav > li > a").slideUp();
})
I just don't know the right syntax for selecting the direct child <a> using $(this)
What I used is this, and I think its wrong...
$(this).find("> a")
Thank you.
For starters, you have an extra quote. Remove the quote after this. Like this:
$(this).find("> a")
Admittedly I've never used selectors for this case, so I can't comment about why it's not working. Instead, I'd recommend using children() which is usually faster and, IMHO, clearer.
$(this).children('a');
But if you really want to use a string selector, this should work:
$('> a', this)
Note that the jquery docs say that the latter code will be deprecated at some point, so use with caution. I'd still recommend using children().
You can use $(this).children("a:first") if you just want the first a tag as well
Related
I'm reading a book and they show a couple of examples of how to select elements on the DOM, but they advise to always use Jquery trasversing methods over the selectors, for example if you have a list inside a div instead of using
$("#myList > li")
You should use
$("#myList").children("li")
Most of the time I use the first over the latter, the author says the 2nd is prefered and more efficient but he does not address why, can anyone explain the reason behind this?
I think the difference in performance in that particular case comes down to this:
document.querySelectorAll('#myList > li');
// VS
document.getElementById('myList').children;
And the performance test here: http://jsperf.com/ae-d2-56-2a-e2-36-a3-d3-52-74
jQuery might check to see if it's a li given the selector but that's still going to be faster than querySelectorAll or Sizzle.
I realize the question title is a bit confusing, but in reality, I mean to ask exactly what I've typed.
I am trying to write a CSS file for printing (nausea rising) and I am wanting to eliminate white space in unnecessary rows (the necessity, or rather, the lack thereof, is determined by input fields that have empty values).
The proper CSS syntax (if there exists any) is relentlessly eluding me.
I have used selectors like this before:
input[type=text]
So I could assume (hopefully... gulp!) that I could use something like:
input[val='']
However:
1) I'm not sure using apostrophes/quotes is even legal inside those brackets (what's that area of a CSS selector called, again?)
2) I wouldn't know how to put a selector inside those brackets (if even possible) since the actual "tr"s are what I'm trying to target, just "tr"s with td children with input children with empty vals.
Wallowing in random syntax, I tried:
tr[td input val=]
Very much NOT to my surprise, did I find that obviously this didn't work, then I realized I had no clue how to proceed, if I wanted to accomplish this strictly in CSS.
~ Takes a quick breathe
Okay, I realize I'm asking a lot out of CSS, but if it's selector system wasn't so powerful I wouldn't even assume this possible.
Lastly, I am already implementing javascript, jQuery, and even server-side C#.net (WebMatrix) so if this answer is best solved using these other languages, I don't mind, I just want the simplest cleanest solution, if possible, as any scripting method I use will require the addition of another class to all td elements therein, and there are many, not to mention the scripting itself.
Any help, as always, is greatly appreciated.
---------------------EDIT REGARDING ALNITAK'S ANSWER------------------------
I tried to add the following jQuery just before my window.print(); JavaScript command:
$('tr > td > input[value=""]').parent().parent().css('display', 'none');
$('tr > td > input[value=""]').parent().parent().css('visibility', 'hidden');
I have checked my # of parents, and all is as it should be there. The only other thing that might be interfering is that I have razor embedded in the values by default (although they are explicitly assigned empty strings on page start so, it should be fine). Just in case though I also tried:
$('tr > td > input[value=null]').parent().parent().css('display', 'none');
$('tr > td > input[value=null]').parent().parent().css('visibility', 'hidden');
But, alas, to no avail.
You can't do this with pure selectors, because the end result of a selector is always the matching child node, not their ancestors.
You need to find those matching child nodes, and then climb back up the tree again, e.g. in jQuery:
$('tr > td > input[value=""]').parent().parent().css('color', 'red');
You can use .closest('tr') instead of .parent().parent() if you prefer.
Also using jQuery, you can use the .has() function to create a chain that matches elements containing particular children:
$('tr').has('> td > input[value=""]').css('color', 'red');
The .has() function is more efficient than using the :has pseudo-selector, although I would expect neither to be as efficient as the full selector above which takes advantage of document.querySelectorAll on modern browsers.
If you can't get the input[value=""] part to work, try this:
$('tr > td > input').filter(function() {
return this.value == '';
})....
If I'm understanding you correctly :
You can't do what you want to in CSS, not yet anyway.
What you're looking for is a css parent selector.
http://css-tricks.com/parent-selectors-in-css/
By using the selector:
tr td input[value='']
You'll be selecting the inputs, not the <tr>s.
One way to achieve what you want is to have something "watch" the page you're on (from javascript) and apply a class to anything you want hidden, when you print. Then in your print stylesheet just use that class to hide!
Your prose translates to this CSS:
!tr>td>input:matches(:not([value]),[value=''])
However, both ! and :matches are CSS4 selectors that are not implemented yet. You'd be better off using JavaScript:
var qsa = document.querySelectorAll("tr>td>input"), l=qsa.length, i;
for( i=0; i<l; i++) {
if( qsa[i].value == '') qsa[i].parentNode.parentNode.style.display = "none";
}
Try using the :has() selector: http://api.jquery.com/has-selector/
Description: Selects elements which contain at least one element that matches the specified selector.
$('tr:has(td input[value=""])').css({color:'red'});
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();
i was wondering things...
If i need to get the content or append an click function to an div, as the structure of the selectors it's something like that:
$('body #content #sidebar .modalwindow #global-content')
i want to target #global-content, the final id of the selectors.
what its better?
Just target it as $('#global-content') and do what i wanna or give to it all the path?
$('#global-content') is the best selector to use, altough maybe the whole selector will be executed the same way (if jQuery starts from right to left, which I'm not sure it does). ID should be unique and getElementById() is the fastest native browser method, so $('#global-content') is the fastest possible selector.
Keep in mind also, that when you are searching for something exactly 1 level lower in the DOM tree, you can put > in the selector. Example:
$('body .content') is equialent to $('body').find('.content')
$('body > .content') is equialent to $('body').children('.content')
The second one is faster.
You can experiment and try out your selectors here
a similar question was asked in
jQuery Selectors, efficiency
the answer is that
$('#global-content')
is faster
if you know the id of your element and if your id is really unique (as it should be). It is faster to call directly the id >> $('#global-content').
Thus, it is interpreted by jquery to one of the fastest selector getElementById() instead of filtering the DOM.
Note: I know jquery 1.5 and higher (maybe even since 1.4) were optimized to select by id even if the jquery code was adding too much information but that's not the best way to rely on the framework to correct a bad coding
I need to retrieve the first element.
I do that with this code...
$(element).find('.x').first();
As much as I understand, that code...
Retrieves all elements from element that matched .x,
Removes unneeded elements;
Is there any better way to do it? Like $.findOne() or something?
As per jQuery docs:
Because :first is a jQuery extension and not part of the CSS
specification, queries using :first cannot take advantage of the
performance boost provided by the native DOM querySelectorAll()
method. To achieve the best performance when using :first to select
elements, first select the elements using a pure CSS selector, then
use .filter(":first").
So rewriting your selector to:
$(element).find('.x').filter(":first")
or (this one will give you direct descendants only and will be faster than .find, unless you're looking for nested elements too)
$(element).children('.x').filter(":first")
should give you better results.
Update After valuable inputs from kingjiv and patrick dw (see comments),
it does seem that these two are faster than .filter(':first') contrary to what the doc claims.
$(element).find('.x').first(); // faster
$($(element).find('.x')[0]); // fastest
If you want to have it real fast, you should use native browsers methods. Modern browsers support querySelector [docs]:
var $result;
if(element.querySelector) {
$result = $(element.querySelector('.x'));
}
else {
$result = $(element).find('.x').first();
}
The usage is a bit limited, as it would only work if element is a single element and if the selector is a valid CSS selector. You could make a plugin out of it. But then, if you consider all cases, like multiple elements etc., there is probably no advantage anymore.
So again, if you have a very specific use case, this might be useful, if not, stick with jQuery.
Update: Turns out, making a plugin is still faster: jsPerf benchmark
(function($) {
$.fn.findOne = function(selector) {
try {
var element, i = 0, l = this.length;
while(i < l && (element = this[i].querySelector(selector)) === null) {
i++;
}
return $(element);
}
catch(e) {
return this.find(selector).first();
}
};
}(jQuery));
How this works:
The plugin iterates over the selected DOM elements and calls querySelector on each of them. Once an element is found, the loop will terminate and return the found element. There are two reasons an exception could occur:
The browsers does not support querySelector
The selector is not a pure CSS selector
In both cases the plugin will fall back to use the normal jQuery method.
As crazy as it seems, in every performance test I've seen, .first() has better performance than :first.
As most people are suggesting, it seems as though using $(element).find(".x:first") should have better performance. However, in reality .first is faster. I have not looked into the internals of jquery to figure out why.
http://jsperf.com/jquery-select-first
And apparently using [0] and then rewrapping in a jquery object is the fastest:
$($(element).find(".x")[0])
EDIT: See mrchief's answer for an explanation of why. Apparently they have now added it to the documentation.
This should be better
$(element).find('.x:first');
Use :first selector:
$(element).find('.x:first')
It's better to write:
$('a:first');
What you're writing is "in 'element', find '.x' and return the first one". And that can be expressed like this
$('.x:first', element);
how about using first-child pseudo class ? like
$(element).find('.x:first-child')
However it might generate issues if your structure is like
<div>
<p></p>
</div>
<div>
<p></p>
</div>
so actually it is not what you are looking for (if you mean general solution). Others mnetions :first and this seems to be the correct approach
Your bottleneck is really the .find(), which searches all the descendants instead of just the immediate children.
On top of that, you're searching for a class .x (which uses a jQuery custom search) instead of an ID or a tagname (which use native DOM methods).
I would use Mrchief's answer and then, if possible, fix those two bottlenecks to speed up your selector.
You could combine the $(element) and .find() calls using a descendant selector; I'm unsure of the performance comparison:
$("#element .x").first().hide();
That way is fine according to the jQuery documentation, or at least better than using :first selector.
You can try as alternatives .filter(":first") or get the first element using array accessor against the .find() result [0].
Also, instead of .find() you can change it to:
$('.x', element)
To narrow the search to .x elements inside element, intead of searching the whole document.