Working with jQuery Collections - javascript

I'm trying to increase my understanding of jQuery. Please consider the following code.
if ($('.myClass').data('id') == '123') {
}
How does this work? It looks simple enough until you understand that $() returns a collection of elements. So what does the code above do exactly? How does it make sense to compare the value of the data-id attribute for a collection of elements like this?
(I understand I can use each() to explicitly test each element in the collection. My question is about what the code above does.)

.data('id') returns the value for the first item in the collection, but .data('id','xyz') will set the value for all items in the collection - much the same behaviour as other jQuery methods like .html(), .text(), etc.
It may not seem to make sense to just test the first in an if statement like that, but it makes more sense for cases where you know there will be exactly one element, for example when your selector is an id, or when you use $(this).data('id') inside an event handler or something.
If you are asking how to test whether all items in the collection have a particular data value you can do this:
var $col = $('.myClass');
if ($col.length === $col.filter(function(){return $(this).data('id') === '123';}).length) {
// do something
}
Or if you just want to know if at least one has that data value:
if ($('.myClass').filter(function(){return $(this).data('id') === '123';}).length > 0) {
// do something
}

I believe if you're trying to get a value through a jquery function, it returns the value from the first item in the collection. for example if you have:
<div class='1'></div>
<div class='2'></div>
<div class='3'></div>
and you run:
$('div').attr('class');
it will return "1". I don't know if this is uniform through all jQuery functions, but this is the expected behavior.

You can use jQuery .each() - http://api.jquery.com/jQuery.each/
Example in comments since stackoverflow doesn't like jsFiddle that much.

Related

Copy value from one text field to another when button clicked

I am trying to get one field to copy over to another field when a div is clicked on, and the code that I have currently is not working. It's showing '0' in field1, even though field2 is set to 1 by default.
$(document).on('click', '#button', function() {
$('#textfield1').val === "document.getElementById('#textfield2').value";
Try with:
$(document).on('click', '#button', function() {
$('#textfield1').val($('#textfield2').val())
});
You're using an odd mix of JS and jQuery here.
Your main issue is that val() is a method, not a property. Therefore your code should look something like this:
$(document).on('click', '#button', function() {
$('#textfield1').val($('#textfield2').val());
});
I'd strongly suggest you familiarise yourself with the jQuery documentation, specifically val() in this case.
It's showing '0' in field1, even though field2 is set to 1 by default.
You were assigning a string to $('#textfield1').val method which is why your code was not having any effect on textfield1's value.
Make it
$(document).on('click', '#button', function() {
$('#textfield1').val( $('#textfield2').val()); //use jquery val method
}
Generally speaking, JQuery offers only functions, and not properties (as #Craicerjack stated), hence remove that === and pass the new value as an argument, as follows:
$('#textfield1').val("yourText");
Also, you're passing a CSS selector rather than just an element ID to the Document.prototype.getElementById() function. Remove that # qualifier!
Moreover, you shoudln't be using a stringified JavaScript expression as a value, otherwise you'll get that exact JS expression as the input value. Rather, don't put those quotes around the expression, so that the interpreter will be evaluating it. Below is some working code.
$('#textfield1').val(document.getElementById('textfield2').value);
However, as #Rory McCrossan pointed out, you're using an odd mix of plain DOM and JQuery, and that makes no sense. It would be more consistent to also read the value of the other text field using JQuery, as follows:
$('#textfield1').val($('#textfield2').val());
Alternatively, you may do not need JQuery and opt for the standard DOM interfaces like in the example below:
document.getElementById('textfield1').value = document.getElementById('textfield2').value;

better performance for jquery $.each loop

Using select2 plugin (http://select2.github.io/select2/)
This searches through all option values for the $selectstring variable and then selects the ones found. If its searching over 200 option values it takes about 5-6 seconds...im trying to reduce this.
Is there a way to speed up my search element for containing-string code?
Is it true that using a for loop instead of $.each would be better performance?
jquery:
$('#selectbutton').click(function() {
var selectstring = $('#selectstring').val();
if (!selectstring.trim())
return false;
stringVal.push($('#projadd\\[\\]').val());
$('#projadd\\[\\]').find('option').each(function(){
if($(this).is(':contains(' + selectstring + ')')){
stringVal.push($(this).val());
}
$('#projadd\\[\\]').val(stringVal).trigger("change");
});
$('#selectstring').val('');
});
The problem here is not the .each() but your code in general. You are creating a lot of jQuery object when there is no need to it. You are also assigning a value to an element multiple times in the each when it should be outside of it.
Try avoiding jQuery when you can easily do it vanilla. Also try avoiding :contain since it is a costly selector.
Go with a code that look like that :
$('#selectbutton').click(function() {
var selectstring = document.getElementById('selectstring').value; //Reduced the number of function call and doesn't create a jQuery object.
if (!selectstring.trim())
return false;
var $projadd = $('#projadd\\[\\]');//You use it more than 1 time? Cache it
stringVal.push($projadd.val());
$projadd.find('option').each(function(){
if(this.textContent.indexOf(selectstring) > -1){ //Don't use :contains, use native Javascript methods
stringVal.push(this.value); //Do not create jQuery object, acces value property. Accessing properties is always faster than calling a function.
}
});
$projadd.val(stringVal).trigger("change"); //Move it out of the .each, you only need to set the value once.
document.getElementById('selectstring').value = ''; //Same reason as above.
});
Is it true that using a for loop instead of $.each would be better performance?
Yes, but it's small part of time spent in your loop.
Is there a way to speed up my search element for containing-string code?
Yes, you can use searching in element textContent without jQuery.
$('#projadd\\[\\]').find('option').each(function(){
if(this.textContent.indexOf(selectstring) !== -1){
stringVal.push($(this).val());
}
$('#projadd\\[\\]').val(stringVal).trigger("change");
});
Anyway, this code is quite buggy because eg. .val(stringVal) sets element value to array (is it intended? I don't think so).
First of all try reducing the numbers of object fetching calls inside the loop.
then the baseline is this:
For loop is faster.
You may get at least 40% better performance using for loop with assigning values inside the loop.
Please see these online tests : http://jsperf.com/for-vs-foreach/75
Note: If you care about performance, first create a model of your script then test it in various conditions using some framework, jsperf for eg.

What does $($(this)) mean?

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.

How do I find out whether an element with that ID exists or not?

I do a:
console.log($('#test'));
I know that test doesn't exist. If I do a console.log, it doesn't output undefined/null. Rather it ouputs something like an empty array and when I check that array it looks like it returns the jQuery object itself.
I also tried:
if ($('#test')){
//do something
}
But it still doesn't work. I want to know whether the ID I am selecting exists on page or not. How do I do that using jQuery?
It's something like 20x faster to do this:
if (document.getElementById("test"))
compared to the jQuery operation to just determine if a DOM object with that id exists in the page. jQuery can do a lot for you, but when its general selector engine and general object structure isn't needed, it's not the quickest way to do things.
As others have said, $("#test") is always a valid jQuery object, even if #testdoesn't exist. If the #test object doesn't exist, then $("#test") will be a jQuery object that has no DOM objects in it (the internal array will have a .length === 0), but it's still a valid object.
In JavaScript, objects are always truthy, so using it in that fashion will always pass the condition.
You need to check the length property. A response of 0 is falsy, and will work as expected.
if ($('#test').length) {
// ...
}
This is unlike document.getElementById(), which returns null if the element with that id attribute does not exist.
If this is confusing, you could always write a quick jQuery plugin.
$.fn.exists = function() {
return !!this.length;
};
You can then call exists() on a jQuery collection, to ensure that selector has matched at least one item.
Use '(' and ')' for 'if' statements, and check if the returned array has length greater than 0:
if ($('#test').length > 0){
//do something
}
use something like this
if ($('#test').length > 0){
alert('hi')
}else
{
alert('hello')
}
Live Demo ​
Use
if ($('#test').length > 0){
//do something
}
the length tells you how many items were selected if it is 0 no element has the id test.
best way for this is to check length of the selected element
if ($('#test').length > 0){
//do something
}
But if you want to create a exist function jQuery welcomes you just add the line in your script
jQuery.fn.exists = function(){return this.length>0;}
and now you can Check if element exist or not
if ($(selector).exists()) {
// Do something
}
console.log($('#test'));
This won't print the value because it represents the object found in the DOM with the id test.
If you want to get values, use $("#test").val(); or $("#test").html();
If you want to check existence, do the length test as suggested above.
Also, if you're testing for the existence of a generated element (something you added to the DOM), make sure you checkout .live (http://api.jquery.com/live/). This is need for all elements that are created after the page is loaded.

Creating Javascript object from JQuery object

Currently I'm unit testing the following code:
if ($(selectedElement).innerText == 'blah')
{
// do something
}
with selectedElement being an anchor object selected from the UI.
In my test code, I have created a DOM structure which has that anchor in the proper position ready to be selected. The problem here is that since selectedElement is originally a javascript object, I need to convert the anchor I got from the DOM structure (which is a JQuery object) in order to get into the above condition.
I have tried the following, with no success:
// DOM structure using HtmlDoc
/*:DOC += <span id='testSpan' class='testSpanClass'><a href='#' id='selectedElem'>blah</a></span> */
selectedElement = $('#selectedElem')[0];
My goal is to be able to use a normal Javascript object to satisfy the condition, and also be able to switch it back to a jQuery object to satisfy conditions further down the function. But if there is a better approach I'll give it a go.
Does anyone have any ideas on how to go about this problem?
EDIT: Is there a solution that does not require changing of the code? selectedElement is actually a global variable.
Thanks.
I am not sure what browser you are testing in, but innerText is an IE only property. Since you are already using jQuery, I would suggest you just call the .text() method on the selected element like this:
selectedElement = $('#selectedElem')[0]; // Get DOM element
if ($(selectedElement).text() == 'blah')
{
// do something
}
You're method of getting the DOM object is fine: $('#selectedElem')[0] or $('#selectedElem').get(0) are equivalent, but the first one is faster in large loops.
jQuery's get method returns the original DOM elements for that jQuery object.
I think perhaps you need to use $('#selectedElem').get(0)
can you use jquery's .html() ?
if ($(selectedElement).html() == 'blah')
{
// do something
}
otherwise, without changing code:
var selectedElement = $('#selectedElem')[0];
if (selectedElement.innerHTML == 'blah')
{
// do something
}

Categories

Resources