I was just poking around with jQuery, and I stumbled upon the Find function.
I tested like this:
$(document).ready(function(){
$('button').click(function(){
$('div').find('div').fadeOut(2000);
});
});
And this
$(document).ready(function(){
$('button').click(function(){
$('div div').fadeOut(2000);
});
});
And both produce the exact same result.
Whats the difference? :)
In your example there is no difference but there are cases that you can not use the first one, for example let't say you have an element as the parameter of a function and you want to find divs inside it, then you have to use the "Find" method.
function foo(index, el)
{
$(el).find("div")...
}
But when you know the exact path, obviously the second approach is more robus.
There is no difference.
If you already have a jQuery object, the find method is useful.
Otherwise, a single selector is simpler.
Most selectors have method equivalents (.children(), .first(), .not()) for this reason.
The method versions also allow you to call .end() to go back to the previous object.
They both do exactly the same thing, but in older browsers where document.querySelectorAll() is not available (Old IEs) $("div").find("div"); is quicker, as Paul Irish confirms in this comment here.
Another thing to note is that in jQuery you can also do this:
$("div", "#some-element")
Which would search for div inside of #some-element. jQuery actually converts this into:
$("#some-element").find("div")
So it's always suggested to use .find() rather than pass in a context.
In this specific case, they do the same thing. Note that find() will traverse all the descendants of the matched elements.
Related
I saw some code around the web that uses the following statement
if ($($(this)).hasClass("footer_default")) {
$('#abc')
.appendTo($(this))
.toolbar({position: "fixed"});
}
What is the use of $($(this)) and why is that necessary here?
Yes, $($(this)) is the same as $(this), the jQuery() or $() function is wonderfully idempotent. There is no reason for that particular construction (double wrapping of this), however, something I use as a shortcut for grabbing the first element only from a group, which involves similar double wrapping, is
$($('selector')[0])
Which amounts to, grab every element that matches selector, (which returns a jQuery object), then use [0] to grab the first one on the list (which returns a DOM object), then wrap it in $() again to turn it back into a jQuery object, which this time only contains a single element instead of a collection. It is roughly equivalent to
document.querySelectorAll('selector')[0];, which is pretty much
document.querySelector('selector');
You can wrap $ as many times as you want, it won't change anything.
If foo is a DOM element, $(foo) will return the corresponding jQuery object.
If foo is a jQuery object, $(foo) will return the same object.
That's why $($(this)) will return exactly the same as $(this).
There is no specific need for double-wrapping and $($(this)) is exactly the same as $(this).
That said, I once found this double-wrapping in one file in my project, committed by another developer. Tracking the changes through revision, turned out that it started as $($(this).find('selector').first()) - that is, the result of some selector was wrapped to create a new object. Then for whatever reasons, the selector was removed and only the double-wrapping of this remained. Needless to say, on the next commit it was changed to $(this).
As explained before me, $($(this)) and $(this) are absolutely identical. jQuery returns the same jQuery object if you try to wrap it more than once.
Additionally, for performance considerations it is a good practice to reuse jQuery objects - it is quite expensive to create jQuery objects, especially the ones with complex selectors. Example:
var $this = $(this);
if ($this.hasClass("footer_default")) {
$('#abc')
.appendTo($this)
.toolbar({position: "fixed"});
}
Just google for 'jQuery best practices' - it will take a 30 min for you to learn these basics and you will use jQuery way more effectively.
There is no meainig of doing that.
The following code return the same:
console.log($($(this)).hasClass("footer_default"))
console.log($(this).hasClass("footer_default"))
a boolean value depenging on if the selected element has or not the class footer_default:
.hasClass( className )Returns: Boolean
Demo: http://jsfiddle.net/IrvinDominin/aSzFn/
$(this) and $($(this)) both return jquery object.
There is no difference between these two.
I recently learned (here on stackoverflow : ) ) that when using jquery every time I write
$("...")
a DOM search is performed to locate matching elements. My question is very simple: how do I efficiently perform a series of actions (using the nice methods of jquery objects) on a DOM element I have located with jquery? Currently, I was doing (eg):
var previousHtml = $("#myDiv").html();
$("#myDiv").addClass("tangoClass");
$("#myDiv").html("bla bla bla");
//...
Basically, I was always referring to the element by writing $("#myDiv"). How can I repeatedly manipulate a DOM element (using jquery functions, rather than vanilla Javascript) in an efficient way? Does the following avoid the costly DOM searches?
var myDiv = $("#myDiv");
var previousHtml = myDiv.html();
myDiv.addClass("tangoClass");
myDiv.html("bla bla bla");
Or should I instead try chaining the jquery calls as much as possible, eg:
var previousHtml = $("#myDiv").addClass("tangoClass").html(); //saves me 1 $("#myDiv") call
$("#myDiv").html("bla bla bla");
Thank you for any insight. : )
lara
I also agree that chaining is the best method to use, but something else no one has address here is using .andSelf()(1) and .end()(2) while chaining.
The following adds the "border" class to both the div and the p contained within.
$("div").find("p").andSelf().addClass("border");
Using .end() "resets" the selector
$("div")
.find("p").addClass("myParagraph").end()
.find("span").addClass("mySpan");
Update: .andSelf() has been deprecated and essentially renamed to .addBack(), use it in the same manner.
Every time you use a jQuery function, it returns the full jQuery object from the initial query. This lets you chain actions together, so the actual query only happens the first time.
From your examples, it doesn't look like you ever use previousHtml, so you don't need to grab it at all. I think you can just do this:
$("#myDiv").html('bla bla bla').addClass('tangoClass');
It depends on which functions you are calling on that element, since not all functions will return the DOM element. However if all the functions you have to call will always return the DOM element, then it might certainly make your code more readable.
Yes I would recommend to use chaining, because the jQuery methods usually return the element you modified, so it doesn't need to be looked up in the DOM again. And I find it more readable, too (you know which operations belong to which element).
Just because no one mentioned it, using your first method will also work and save the DOM search.
However, chaining, as the others said, would be the more "proper" way of using the same element and applying different actions to it.
Good luck!
the two are the same.
var myDiv = $("#myDiv"); // $("#myDiv") runs document.getElementById,
// wraps the DOMElement, returns the wrapper.
myDiv.addClass("tangoClass"); // obviously reuses the object
myDiv.html("bla bla bla"); // ditto
chaining is exactly the same because jQuery methods return this, the object that they're attached to:
myDiv
.addClass("tangoClass")
.html("bla bla bla")
;
you can test this with (myDiv === myDiv.html("bla bla bla"))
to answer your question "which should I use": DRY (Don't Repeat Yourself) would suggest chaining. just don't forget readability (don't lump many method calls into a single line; my recipe for readability is above)
Using jQuery what's the way to get all elements of a queried set EXCEPT the first. I forget offhand.
You can do:
$(selector).not(':first');
Or:
$('selector:not(:first)');
I believe you are refering to the NOT selector .
$("div.someClass:not(div.someClass:first)")
Assuming of course you are looking for div.someClass. This might be a bit verbose, but I think it works. Haven't tested.
Another option is the gt selector (greater than):
$('selector:gt(0)');
or
$('selector').gt(0);
:not(:first) is more readable, but also a bit longer.
You could also use the splice method, e.g.
var nodes = $(selector);
nodes.splice(0, 1);
Are the following exactly equivalent? Which idiom do you use and why?
$('#form1 .edit-field :input')
$('#form1 .edit-field').find(':input')
$('.edit-field :input', '#form1')
$(':input', '#form1 .edit-field')
I would use either #2 or #4:
$('#form1 .edit-field').find(':input')
$(':input', '#form1 .edit-field')
Both of the above are essentially the same. Behind the curtain when you specify a context this is what's happening anyway:
jQuery( context ).find( selector );
The reason I would avoid #1 and #3 is because they're both significantly slower than #2/#4.
EDIT: Just did a quick test:
1000 input elements using YOUR selectors:
$('#form1 .edit-field :input') // 55ms
$('#form1 .edit-field').find(':input') // 21ms
$('.edit-field :input', '#form1') // 47ms
$(':input', '#form1 .edit-field') // 18ms
The first two are equivalent when comparing element selection. However, the second form, when used in a command chain with a correspoding end() call, can be used to select further child elements within "#form1 .edit-field", i.e.:
$('#form1 .edit-field').find(':input')
...
.end().find(':hidden')...
.end()...
I'm uncertain about the second two forms, actually, I beleive they are not valid. Correct me if I'm wrong, but based on the docs, the correct syntax would look like this:
$('.edit-field :input', $('#form1'))
$(':input', $('#form1 .edit-field'))
Either way, IMHO these are less consise ways of saying the same.
In summary, generally I'd stick to the first form, unless you exploit the advantage of the second to traverse further children, as explained above.
The more I code in jQuery, the less I use selectors and the more I traverse instead. I would do:
$('#form1').find('.edit-field').find(':input')
It's longer, but conveys the selection process better with a bit more meaning for each step. Traversing is more favorable for chaining, and it makes end() useful.
I would use different forms based on what I already have and what elements I also need to work with. For example, if I need to work with other fields in the same form, I'll save a reference to the $('#form1') to save searching for it multiple times.
We're considering switching our site from Prototype to jQuery. Being all-too-familiar with Prototype, I'm well aware of the things about Prototype that I find limiting or annoying.
My question for jQuery users is: After working with jQuery for a while, what do you find frustrating? Are there things about jQuery that make you think about switching (back) to Prototype?
I think the only that gets me is that when I do a selection query for a single element I have to remember that it returns an array of elements even though I know there is only one. Normally, this doesn't make any difference unless you want to interact with the element directly instead of through jQuery methods.
Probably the only real issue I've ever ran into is $(this) scope problems. For example, if you're doing a nested for loop over elements and sub elements using the built in JQuery .each() function, what does $(this) refer to? In that case it refers to the inner-most scope, as it should be, but its not always expected.
The simple solution is to just cache $(this) to a variable before drilling further into a chain:
$("li").each(function() {
// cache this
var list_item = $(this);
// get all child a tags
list_item.find("a").each(function() {
// scope of this now relates to a tags
$(this).hide("slow");
});
});
My two pain points have been the bracket hell, can get very confusing
$('.myDiv').append($('<ul />').append($('<li />').text('content')));
My other common issue has to do with the use of JSON in jQuery, I always miss the last comma,
$('.myDiv').tabs({ option1:true, options2:false(, woops)});
Finally, I've been using jQuery for about 6 months now and I don't think I'll ever go back to prototypes. I absolutely love jQuery, and a lot of the tricks they use have helped me learn a lot. one cool trick that I like is using string literals for method calls, I never really did that too much with prototypes.
$('.myDiv')[(add ? 'add' : 'remove') + 'Class']('redText');
(The only thing I can think of is that this is the element instead of a jQuery object in $("...").each(function)-calls, as $(element) is more often used then just the element. And that extremly minor thing is just about it.
Example of the above (simplified and I know that there are other much better ways to do this, I just couldn't think of a better example now):
// Make all divs that has foo=bar pink.
$("div").each(function(){
if($(this).attr("foo") == "bar"){
$(this).css("background", "pink");
}
});
each is a function that takes a function as parameter, that function is called once for each matching element. In the function passed, this refers to the actual browser DOM-element, but I find that you often will want to use some jQuery function on each element, thus having to use $(this). If this had been set to what $(this) is, you'd get shorter code, and you could still access the DOM element object using this.get(0). Now I see the reason for things being as they are, namely that writing $(this) instead of this, is hardly that cumbersome, and in case you can do what you want to do with the DOM element the way it is is faster than the way it could have been, and the other way wouldn't be faster in the case you want $(this).)
I don't think there are any real gotchas, or even any lingering annoyances. The other answers here seem to confirm this - issues are caused simply by the slightly different API and different JavaScript coding style that jQuery encourages.
I started using Prototype a couple of years ago and found it a revelation. So powerful, so elegant. After a few months I tried out jQuery and discovered what power and elegance really are. I don't remember any annoyances. Now I am back working on a project using Prototype and it feels like a step back (to be fair, we're using Prototype 1.5.1).
If you reversed the question - "What Prototype annoyances should I be aware of as a jQuery user?" - you would get a lot more answers.
Nope. Nada. Nyet.
.each:
jQuery (you need Index, even if you're not using it):
$.each(collection, function(index, item) {
item.hide();
});
Prototype (you're usually using the item, so you can omit the index):
collection.each(function(item) {
item.hide();
});
This is really only an annoyance if you're doing a lot of DOM manipulation. PrototypeJs automatically adds its API to DOM Elements, so this works in prototypejs (jQuery of course doesn't do this):
var el = document.createElement("div");
el.addClassName("hello"); // addClassName is a prototypejs method implemented on the native HTMLElement
Even without running the native element through the $() function.
PS: Should note that this doesn't work in IE.