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.
Related
I was just wondering which is the correct or most efficient way of navigating through the Dom using variables.
For example, can I concatenate selectors
var $container = '.my-container';
$($container).addClass('hidden');
$($container + ' .button').on('click', function(){
//something here
});
or should I use the jQuery traversal functions
var $container = $('.my-container');
$container.addClass('hidden');
$container.children('.button').on('click', function(){
//something here
});
Is there a different approach, is one best, or can you use them at different times?
The $ is usually used only when working with an actual jquery object. You generally shouldn't prefix anything with that unless it's really something from jquery.
Beyond that little bit though, performance-wise, your second bit of code is going to be faster. I made an example jsperf here: http://jsperf.com/test-jquery-select
The reason the second bit of code is faster is because (if I remember correctly) jquery caches the selection, and then any actions performed on that selection are scoped. When you use .find (which is really what you meant in your code, not .children), instead of trying to find elements through the entire document, it only tries to find them within the scope of whatever my-container is.
The time when you wouldn't want to use the second pattern is when you expect the dom to change frequently. Using a previous selection of items, while efficient, is potentially a problem if more buttons are added or removed. Granted, this isn't a problem if you're simply chaining up a few actions on an item, then discarding the selection anyway.
Besides all of that, who really wants to continuously type $(...). It's awkward.
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 been searching but I can only find articles talking about one or the other. Which one is better?
I'm making a small web app where performance is not a big concern since there's nothing complex going on.
I considered using jQuery's val() function since maybe it solves some inconsistency I'm not aware of, but getElementById.value IS faster (although the end user won't notice.)
So which one should I use? Is jQuery's non-native method worth the lower performance to gain more compatibility?
The biggest advantage of using jQuery().val() over document.getElementById().value is that the former will not throw an error if no elements are matched, where-as the latter will. document.getElementById() returns null if no elements are matched, where-as jQuery() returns an empty jQuery object, which still supports all methods (but val() will return undefined).
There is no inconsistency when using .value for form elements. However, jQuery.val() standardises the interface for collecting the selected value in select boxes; where as in standard HTML you have to resort to using .options[this.selectedIndex].value.
If you're using <select> elements as well, .value won't work whereas .val() will.
I would not mind about performance of just getting a value. If you want the best performance, perhaps you shouldn't use a library at all.
jQuery does so many nice little error handling things (look below) that I would never write a line of javascript without jquery in a browser again.
First, val works on checkbox groups, selects, gets html, and the
like.
Second, $ lets you use sizzle selectors, so in the future, you can
easily switch between an ID and a CSS path.
Third, your code will be so much easier to read and maintain if you
just use jQuery, that the time you save maintaining your code
outweighs any speedup that you admit your users won't see. Finally,
jQuery is a very popular, very widely used library. They will make
$ and val as fast as they can.
I think using pure Javascript is quicker for the following reasons:
You won't have to learn more than pure js
If you don't want errors, use catch(exeption) (I think...)
You don't have to put in that little extra time to type in the code to initiate jquery
The browser responds quicker if you don't use jquery
Normal js works (in a better way) on checkboxes #johndodo
Thank you for listening to my answer.
I've been looking into the performance differences with this recently and, slightly unsurprisingly, using vanilla JS to grab a value is faster than using jQuery. However, the fallbacks that jQuery provides to prevent errors, like what #Matt mentioned, is very useful. Therefore, I tend to opt for the best of both worlds.
var $this = $(this),
$val = this.value || $this.val();
With that conditional statement, if this.value tries to throw an error, the code falls back to the jQuery .val() method.
Here https://www.dyn-web.com/tutorials/forms/checkbox/same-name-group.php is an implementation for checkboxes, apparently options just need to be named the same with the array brackets notation in the name i.e.: name="sport[]" then yu get the array inJavascript via: var sports = document.forms['demoForm'].elements['sport[]']
I was looking for a selection type field solution without using jQuery and I came across this solution:
The Selection group is an object: HTMLCollection, and it has a lenght method and a selectedOptions property, which allows you to iterate through its label properties to populate an Array with the selected options, which then you can use:
...
vehicleCol = document.getElementById('vehiculo').selectedOptions;
vehiculos = [];
if (vehicleCol !== undefined) {
for (let i = 0; i < vehicleCol.length; i++) {
vehiculos.push(vehicleCol[i].label.toLowerCase())
}
}
...
I'd use jQuery's val(). Shorter code means faster download time (in my opinion).
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.
I have a page that selects all the elements in a form and serializes them like this:
var filter = 'form :not([name^=ww],[id$=IDF] *,.tools *)';
var serialized = $(filter).serialize();
This works, unless the form gets around 600+ elements. Then the user gets s javascript error saying that the script is running slow and may make their browsers unresponsive. It then gives them the option to stop running the script.
I have tried running the filters separately, I have tried using .not on the selectors, then serializing them, but I run into one of two problems. Either it runs faster without the error, but also does not filter the elements, or it does filter the elements and gives me the slow script error.
Any ideas?
With 600+ elements this is going to be dead slow. You need to offer Sizzle (jQuery's selector engine) some opportunities for optimisation.
First, consider the fact that jQuery can use the natively-supported querySelectorAll method (in modern browsers) if your selector complies with the CSS3 spec (or at least to the extent of what's currently supported in browsers).
With your case, that would mean passing only one simple selector to :not instead of 3 (1 simple, 2 complex).
form :not([name^=ww])
That would be quite fast... although you're not being kind to browsers that don't support querySelectorAll.
Look at your selector and think about how much Sizzle has to do with each element. First it needs to get ALL elements within the page (you're not pre-qualifying the :not selector with a tag/class/id). Then, on each element it does the following:
(assume that it exits if a result of a check is false)
Check that the parent has an ancestor with the nodeName.toLowerCase() of form.
Check that it does not have a name attribute starting with ww (basic indexOf operation).
Check that it does not have an ancestor with an id attribute ending in IDF. (expensive operation)
Check that it does not have an ancestor with a class attribute containing tools.
The last two operations are slow.
It may be best to manually construct a filter function, like so:
var jq = $([1]);
$('form :input').filter(function(){
// Re-order conditions so that
// most likely to fail is at the top!
jq[0] = this; // faster than constructing a new jQ obj
return (
!jq.closest('[id$=IDF]')[0]
// this can be improved. Maybe pre-qualify
// attribute selector with a tag name
&& !jq.closest('.tools')[0]
&& this.name.indexOf('ww') !== 0
);
});
Note: that function is untested. Hopefully you get the idea...
Could you maybe just serialize the whole form and do your filtering on the backend? Also, why-oh-why is the form growing to 600+ fields?
use the :input selector to only select applicable elements..