Currently i selecting elements like jQuery('a#encode-url-button, a#decode-url-button'), is it possible without creating a new function select the same elements in pure js ? Something like document.getElementById('encode-url-button, decode-url-button').onclick = function... ?
Yes, with document.querySelectorAll. It accepts a CSS selector. Most modern browsers support it.
If you really need to support IE7 and earlier, then of course you can just do two getElementById calls and throw away the elements if they're not anchors. (Which is what the selector a#someid does.)
If you're going to operate on the elements, you need to loop through the resulting list from querySelectorAll, since the DOM API doesn't have the "set theory" orientation that jQuery has. So for instance:
var list = document.querySelectorAll("#encode-url-button, #decode-url-button");
var index;
for (index = 0; index < list.length; ++index) {
list[index].onclick = clickhandler;
}
function clickHandler() {
// ....
}
(I don't advocate using DOM0 handlers like that, look at using addEventListener instead, but as you quoted onclick in the question...)
FWIW, 99.99% of the time, it makes no sense to combine an id selector with a tag selector (a#someid), since id values are unique. Just #someid is usually better. Adding the tag to it doesn't make anything faster; in fact, it makes things slower. The only reason for doing it is if sometimes the element will have one tag (say, a), sometimes another (say, I dunno, div), and you only want to get it if it has one but not the other. Very edge case...
Related
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.
I have HTML page with some HTML element with ID="logo". I need to create JS script (with no external libs calls) that will overwrite that html element with other HTML element like "<div id=logo> stuff inside </div>".
Most of the time, it's just the content you want to replace, not the element itself. If you actually replace the element, you'll find that event handlers attached to it are no longer attached (because they were attached to the old one).
Replacing its content
Replacing the element's content is easy:
var element;
element = document.getElementById("logo");
if (element) {
element.innerHTML = "-new content-";
}
The innerHTML property has only recently been standardized, but is supported by all major browsers (probably most minor ones, too). (See notes below about innerHTML and alternatives.)
Replacing the element iself
Actually replacing the element itself is a little harder, but not much:
var element, newElement, parent;
// Get the original element
element = document.getElementById("logo");
// Assuming it exists...
if (element) {
// Get its parent
parent = element.parentNode;
// Create the new element
newElement = document.createElement('div');
// Set its ID and content
newElement.id = "logo";
newElement.innerHTML = "-new content here-";
// Insert the new one in front of the old one (this temporarily
// creates an invalid DOM tree [two elements with the same ID],
// but that's harmless because we're about to fix that).
parent.insertBefore(newElement, element);
// Remove the original
parent.removeChild(element);
}
Notes on innerHTML and other DOM manipulation techiques
There are a number of wrinkles around using innerHTML in certain browsers, mostly around tables and forms. If you can possibly use a library like jQuery, Prototype, etc., I'd do so, as they've got workarounds for those issues built-in.
Alternatively, you can use the various other DOM methods rather than innerHTML (the same ones I used for creating the div and adding/removing, above). Note that in most browsers, doing any significant amount of markup by doing a bunch of createElement, appendChild, etc., calls rather than using innerHTML will be dramatically slower. Parsing HTML into their internal structures and displaying it is fundamentally what browsers do, and so they're highly optimized to do that. When you go through the DOM interface, you're going through a layer built on top of their internal structures and not getting the advantage of their optimizations. Sometimes you have to do it that way, but mostly, innerHTML is your friend.
Do you really need to 'replace' the element or can you just toggle its visibility? This is a technique that's much simpler and will be more efficient. Most importantly it keeps the content (html) separated from the behavior (javascript).
function toggle() {
document.getElementById("logo").style.display="none";
document.getElementById("element_to_show").style.display="block";
}
see T.J.'s answer if you actually want to replace the element.
Do you really need to 'replace' the element or can you just toggle its visibility? This is a technique that's much simpler and will be more efficient. Most importantly it keeps the content (html) separated from the behavior (javascript).
Is there any direct way in JavaScript or jQuery to check if an element is within another one.
I'm not referring to the $(this).parent as the element I wish to find can be a random number steps lower in the tree of elements.
As an example, I would like to check if < div id="THIS DIV"> would be within < div id="THIS PARENT">:
<div id="THIS_PARENT">
<div id="random">
<div id="random">
<div id="random">
<div id="THIS_DIV">
(... close all divs ...)
So in pseudo code:
if($("div#THIS_DIV").isWithin("div#THIS_PARENT")) ...
If there isn't any direct way I'll probably do a function for this but still it's worth asking.
You could do this:
if($('#THIS_DIV','#THIS_PARENT').length == 1) {
}
By specifying a context for the search (the second argument) we are basically saying "look for an element with an ID of #THIS_DIV within an element with ID of #THIS_PARENT". This is the most succint way of doing it using jQuery.
We could also write it like this, using find, if it makes more sense to you:
if($('#THIS_PARENT').find('#THIS_DIV').length == 1) {
}
Or like this, using parents, if you want to search from the child upwards:
if($('#THIS_DIV').parents('#THIS_PARENT').length == 1) {
}
Any of these should work fine. The length bit is necessary to make sure the length of the "search" is > 0. I would of course personally recommend you go with the first one as it's the simplest.
Also, if you are referring to an element by ID it's not necessary (although of course perfectly okay) to preface the selector with the tag name. As far as speed, though, it doesn't really help as jQuery is going to use the native getElementById() internally. Using the tag name is only important when selecting by class, as div.myclass is much, much faster than .myclass if only <div> elements are going to have the particular class.
With jQuery >=1.4 (2010) you can use the very fast function jQuery.contains()
This static method works with DOM elements, not with jQuery elements and returns true or false.
jQuery.contains( container, descendant )
Example: To check if a element is in the document you could do this:
jQuery.contains( document.body, myElement )
Is there another way to get the last child of a div element other than using div:last-child, which does not work in IE8 at least?
In jQuery it's easy:
$("div :last-child")
In pure CSS it can't be done.
Otherwise you're stuck with traversing the DOM in Javascript.
Also note the difference:
"div :last-child": every last child of a div; and
"div:last-child": every div that is a last child.
Unfortunately, I know not a way to do this in CSS without using :last-child, which (as you stated) fails in IE.
If you're talking about javascript, then it's possible using Node.lastChild:
var div = document.getElementById("mydiv");
var lastChild = div.lastChild;
Use jQuery to find the appropriate elements: $("div:last-child").addClass("last-child");
Then use CSS to specify the presentation: div .last-child { /* your rules */ }
You can assign a class 'last' programmatically and select that one or use javascript. You might also have a shot by using some of Microsofts IE only css script thingies. But I do not know much about them, also do not consider that as an option.
I do this with pure JavaScript by looping back through the nodes from the lastChild of the target element. If there is whitespace in your HTML, the lastChild may be a text node, so we loop until we find an element node (node type 1) or until we run out of nodes (previousSibling will return null).
For example, to find the last element in a page, I loop back from the lastChild of the body:
var targetElement = document.getElementsByTagName("body")[0],
lastChildElement = targetElement.lastChild;
while (lastChildElement && lastChildElement.nodeType !== 1) {
lastChildElement = lastChildElement.previousSibling;
}
if (lastChildElement) {
// Do something
}
If there is no element inside the body, lastChildElement will exit this loop as null.
There are some cases in which you definitely don't want to use $("div:last-child") out of the box. One important thing to note is that this won't cater for changes to the DOM after that call - e.g. if a new element is added as the last child, you'll need to update things. It's not just a case of repeating the earlier call, either; you'll need to reverse the initial call on the previous last child.
If you're doing anything vaguely dynamic, be wary of this. the CSS pseudo-class is definitely the superior solution, it just has a horrible lack of support in IE. If your design can cope with the loss of last-child support in IE, and you're using progressive enrichment, I'd highly recommend the CSS approach over JS.
Fast Forward >> 4 years later (2013)
It is now possible with CSS v3 (CSS3) and is supported by all major browsers (with IE being >= version 9).
If you travel back in time with IE <= version 8, then jQuery version < 1.x will sort you out (just as the other answers have pointed out).
Read more http://www.w3schools.com/cssref/sel_last-child.asp
var divs = $("id").getElementsByTagName('div');
var lastChild = divs[divs.length-1];