Whenever I want to find if an element exist in the DOM I use the following code.
if($('#target').length){
// do stuff.
}
This works well and I use it quite a lot on client sites.
Question:
How fast is this method? What are the speed implications when this is used a lot in a project?
You would be much better off using if(document.getElementById('target')) instead. JavaScript is always faster than jQuery (since jQuery is just a bunch of JavaScript hidden under the carpet)
EDIT: If you use it a lot, you can make a custom function:
function idExists(id) {return !!document.getElementById(id);}
Native JS is always faster than a query through jQuery. It just may not be as friendly.
After running a query through jsperf.com, native (querySelectorAll) is 57% faster than jQuery
However, if you use id, jQuery will be faster than querySelectorAll. In any case of id, use document.getElementById to test for an elements existence.
http://jsperf.com/jquery-obj-length
Try searching a DOM element with JQuery context say:
if an element u search say, an Input control, lies with in a table, pass table as your context:
A simple example:
$(function(){
var name= $('#Name','#mytab').val();
alert(name);
});
the jquery engine find the element 'Name' with in 'mytab' and not the entire form
follow this fiddle link : http://jsfiddle.net/NzbJr/10/
Related
In my page I want to change the class name of the div whose id is answer1 in div id=question. How can I do that? Thanks.
$('question1 answer1').addClassName('new_name');
<div id="question1">
<div id="answer1" class="old_name">
</div>
</div>
<div id="question2">
<div id="answer2" class="old_name">
</div>
</div>
So, as it has been pointed out, any selector method requires an iterator of some sort, so you can not just apply a method to all objects returned. You will notice in the documentation for Element.select that this is supposed to alleviate having to explicitly convert the object to an array, but I have not had luck with this on jsfiddle. However, I did try the following:
$('answer2').addClassName('new_name');
And it worked just fine. I don't know if the issue is that you are trying to traverse the DOM in your original element object (by using question1 answer1) and this requires the object/array iterator, or if it's just a hiccup elsewhere in the code. But in your specific example, since you know the id of the actual element you want to change the class of, the above code should work fine without specificing the parent element or using an array index of any kind.
I will admit that prototypejs threw me off because they use the same method names for the Element objects as Enumerable objects, so I saw the first instance of select and thought it looked pretty straight forward. Having now seen that almost every class/method requires you to set up a selector and convert it or manually traverse it, I will definitly say that this would be much easier with jquery and that your initial comment that they are almost the same is specifically not true in this scenario. Perhaps protojs offers some features that jquery does not, perhaps your code is tied to protojs (I worked on a project for a year that had to use YUI, which is a much bigger nightmare, trust me), but jquery is set up to play nice with prototypejs, so in cases like these, I'd consider using both. In jquery, the code would have been:
jQuery.noConflict(); // Avoids $ fight between jquery and prototypejs
jQuery( '#question1 #answer1' ).addClass('new_name');
or, to remove the old one first:
jQuery.noConflict(); // Avoids $ fight between jquery and prototypejs
jQuery( '#question1 #answer1' )removeClass('old_name').addClass('new_name');
Also, prototype has a toggleClass method that is probably also unnecessarilly esoteric, but maybe you should read up on: toggleClassName
And I wouldn't be this pissy about wasting my time on this (because I don't like to consider getting stuck learning a new framework a waste of time) except that their documentation, while attractive, has the worst examples I've ever seen. They all assume you have some fundamental idea without ever a friendly real world example or hyperlink to the difference between an instance and a class, and their examples distinguishing the two are identical. I'm definitely going to take some time out later today to find the real best answer to your question, out of spite and pride, if nothing else, but if it really comes down to having to iterator every time, just use vanilla js and use this framework when it's actually useful.
Simply $('answer1') will get you a reference to the div element that you want. The $ function returns an element with the given id string (or null if none was found). Note that you don't use a selector string when using $ - it only operates on ids.
The $$ function takes in a CSS selector string and returns an array of all matching elements, or an empty array if nothing matched. If you wanted or needed to go that route, you could locate the same div like this:
$$('#question1 .answer1')[0]
Once you have your element reference using either of the above methods, you can use addClassName or removeClassName or any other element methods available.
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.
I have been reading more lately about the efficiency of the different selector engines. I know that jQuery uses the Sizzle engine and this blog post about some jQuery stuff mentioned that the Sizzle engine will break apart your selector into an array then parse left to right.
It then, from right to left, begins deciphering each item with regular expressions. What this also means is that the right-most part of your selector should be as specific as possible — for instance, an id or tag name.
My question is whether it is more efficient to run a selector with just the ID specified or the tag name as well:
var div = $('#someId');
//OR
var div = $('div#someId');
Since I write my CSS in the div#someId form I tend to do my selectors the same way, am I causing Sizzle to perform extra work (assuming QuerySelectorAll is unavailable)?
jQuery and Sizzle optimize the #id selector [source] to document.getElementById(id). I think they aren't able to optimize it like this with the tag#id.
The first is faster.
BTW specifying the tag name for an #id selector is over-specifying, as there can be only one tag with a given id on the document. Over-specifying is slower even in CSS.
Rather than speculating, let's measure it!
Here's a test case with this page loaded, then matching a random element with both methods.
Make sure you scroll right down to the bottom.
http://jsperf.com/which-jquery-sizzle-selector-is-faster#runner
As you might expect, a plain id is faster than a tag qualified one (reduction to getElementByID). This is the same when using classes.
Selecting by ID is massively faster than selecting by class, mainly as IDs are guaranteed to be unique.
If you are using jQuery, you can assume a browser with getElementById. $('#someId') can be converted to document.getElementById('someId'). $('div#someId') won't be, so it will be faster to lose the tag name.
jsPerf demonstrating this. The difference is enormous.
var div = $('#someId'); //should be faster
jQuery will use getElementById() for the above selector
var div = $('div#someId'); //would probably preform slower due to finding all the divs first
jQuery will use getElementsByTagName(), then iterate though the array of elements for the above selector
You should also remember, tag names should definately be used with class selectors (whenever possible)
var div = $('div.myclass') //faster than the statement below
versus
var div = $('.myclass') //slower
JsPerf: http://jsperf.com/jquery-id-vs-tagname-id
The first one is going to be faster because it only has to check the id. The second one runs the same check AND has to make sure the tagname is correct. div#id won't give you the element with id id unless it is a div
You can see from the source code here: http://code.jquery.com/jquery-1.6.2.js in the function init.
The fastest selector is $('') which just returns an empty jQuery object immediately.
$('body') is next, which jQuery converts to document.body
The next is $('#id') which uses document.getElementById('id').
Any other selector such as $('div#id') will just become a call to $(document).find('div#id'). find() is very complex compared to any of those other solutions and uses Sizzle JS to select the div.
How can I find out which FORM an HTML element is contained within, using a simple/small bit of JavaScript? In the example below, if I have already got hold of the SPAN called 'message', how can I easily get to the FORM element?
<form name="whatever">
<div>
<span id="message"></span>
</div>
</form>
The SPAN might be nested within other tables or DIVs, but it seems too long-winded to iterate around .parentElement and work my way up the tree. Is there a simpler and shorter way?
If it wasn't a SPAN, but an INPUT element, would that be easier? Do they have a property which points back to the containing FORM? Google says no...
The form a form element belongs to can be accessed through element.form.
When the element you are using as reference is not a form element, you'd still have to iterate through the parentElement or use some other kind of selector.
Using prototype, you could simplify this by using Element.up():
$(element).up('form');
Other answers to this question have pointed out how to do the same in jQuery.
Why not just use:
var nodesForm = node.form;
?
It works on FF3, FF4, google chrome, Opera, IE9 (I tested myself)
Guess you have to iterate through all elements then.
You can try using jQuery:
$("input").parent("form")
http://docs.jquery.com/Traversing/parent#expr
Regarding Gumbo's Post:
As much as prototype and jQuery are useful, some people don't implement them into their projects.
Could someone please explain why Gumbo's solution was downgraded, other than the fact that he repeated what the OP was originally trying to avoid?
node = document.getElementById(this.id);
while (node.nodeName != "FORM" && node.parentNode) {
node = node.parentNode;
}
To answer the OP's question:
Traversing the DOM is the fastest way to achieve this effect - perceived speed is accomplished by 1) better written JS code, or 2) execution time (if you store the form on page load for that element, you'll still be traversing, but you'll have a quicker call to a stored variable when you need to retrieve that information).
There are no attributes nested in non-form elements that would associate it with the form (span.form does not exist).
If you are using a script (php/perl) to generate your page, and you're going to be making a lot of calls to the form, you could embed the form id in the HTML for that element. Still, a look up would need to occur.
I hope this helps,
vol7ron
You could backtrack in the DOM tree until you get to the right node:
node = document.getElementById("message");
while (node.nodeName != "FORM" && node.parentNode) {
node = node.parentNode;
}
Or a small jQuery (ignoring jQuery itself):
$("#message").parents("form:first")
Other than node.parentNode, I don't believe there is a way to find a specific ancestor of a given node. Most libraries usually do what you describe and iterate up through parentNode.
If you're not using a library like prototype, jquery or Ext, it would probably be a good idea. By now, they've resolved all the incompatibilities and quirks in the DOM to make most operations like this a trifle.