How come the equation in the title is false? How do check if two jQuery selectors point to the same DOM object?
You are comparing two distinct jQuery objects because you call $() twice (once for each side of the equation), and as MooGoo explains jQuery creates new wrapper objects for each time you call it. That's why the comparison ends up returning false.
You can extract a DOM object from each jQuery object by either using get() or array dereferencing, then compare these elements. The following both return true because both identical selectors match the same body DOM element:
$('body').get(0) == $('body').get(0)
$('body')[0] == $('body')[0]
If you want to test against a jQuery selector, use is(). Note that, unless your selectors are identical, the selectors you use may not necessarily match the same DOM elements (it's still better to use the above). This also returns true:
$('body').is('body')
Because jQuery creates a new wrapper object for each $ call, and in Javascript all objects are distinct, even if they have the exact same properties/methods.
On the other hand, document.body == document.body would evaluate to true.
Use $.is()
http://api.jquery.com/is/
Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments...
Unlike other filtering methods, .is() does not create a new jQuery object. Instead, it allows you to test the contents of a jQuery object without modification. This is often useful inside callbacks, such as event handlers...
Related
I'm trying to understand why two jQuery objects are not considered equal. When I pass $(this) to console.log() I get:
w.fn.init [input#company-center.drop-menu-open]
Then when I pass $("#idVal") to console.log() I get the exact same result:
w.fn.init [input#company-center.drop-menu-open]
However, when I do $(this) == $("#idVal"), it returns false.
Is it because of ==? Why does it give me false?
The reason $(this) == $("#idVal") returns false is because $(this) and $("#idVal")) are two distinct object instances (despite the fact they are wrapping the same underlying DOM element).
To determine if the underlying elements of two jQuery objects are equivalent, use $.is():
$(this).is("#idVal") // will return true if this is id=idVal
See the documentation on $.is() for more information.
Every time you call $() it creates a new jQuery object. Since == tests object equality, not content equivalence, they don't compare equal.
You can use the jQuery .is() method:
$(this).is("#idVal");
But you don't even need jQuery for this, just use:
this.id == "idVal"
The reason for this is that internally JavaScript actually has two different approaches for testing equality. Primitives like strings and numbers are compared by their value, while objects like arrays, dates, and plain objects are compared by their reference
Follow this link for more
Ok so I finally have a code example to show this!
if ($('#Snowsports-row')[0].classList.contains("hidden") == false) {
$('#snowsports-only').removeClass("hidden")
}
The code works ONLY as written above, i.e., if the [0] were moved to the second line and removed from the first line, or if it were present/absent in both lines, it would fail.
I understand the output difference...
$('#Snowsports-row')
=> [<div>...]
$('#Snowsports-row')[0]
=> <div>...
...but I'm not understanding under what circumstances you're OK to get an array of element(s) and in which you need to tease out the exact element.
THANKS FOR ALL ANSWERS! Very clearly helped me to figure out that the problem may have been confusing JS/jQuery methods. Final version:
if ($('#Snowsports-row').hasClass("hidden") == false) {
$('#snowsports-only').removeClass("hidden")
}
The .classList method is not widely supported (not in MSIE 9.0 for example) so it's not portable, although where it exists it's fast.
Since every ID in a document is supposed to be unique, and since calling removeClass for a class that isn't present is harmless, just replace your entire call with:
$('#Snowsports-row').removeClass('hidden')
Or better yet, if that class means what I think it does, use .hide() and let jQuery do its job for you, potentially animation the transition in the process.
Alternatively, if you actually wanted to stick with using DOM and classList, you should use the .remove() method that classList already supports:
document.getElementById('#Snowsports-row').classList.remove('hidden')
although there's a minor disadvantage in that this code will crash if that element isn't found (since .getElementById will return null) whereas jQuery silently ignores calls made on empty selectors.
As for the meta-question - you use [n] if you want to access the single DOM element at position n within the jQuery object, as you've done when you use .classList.
You use .eq(n) to obtain a jQuery object representing that DOM element, e.g. if you want to apply jQuery methods to that (single) element.
If there's only a single element, or you want the jQuery method to apply to every matching element, just call the method directly on the selector, as I've done above.
First off, by using jQuery for what it's good at, you can replace this:
if ($('#Snowsports-row')[0].classList.contains("hidden") == false) {
$('#snowsports-only').removeClass("hidden")
}
with this:
$('#Snowsports-row').removeClass("hidden");
Your first block of code does the following:
With $('#Snowsports-row'), make a jQuery object that contains all DOM elements that match the select '#Snowsports-row'.
Then reach into the jQuery object with [0] and get the first DOM object in that jQuery object.
Then, use a property/method on that DOM element to determine if a class exists on that DOM element with your .classList.contains("hidden") reference.
Then, if you find that class, remove it.
A jQuery object contains inside it an array of DOM elements. If you call a method on the jQuery object itself like:
$('.tableRows').html("hello");
Then, you are asking jQuery to operate on ALL the DOM elements inside the jQuery object. You must use jQuery methods, not DOM methods.
If, on the other hand, you want to use a method such as .classList.contains(), that is only a method on an actual DOM element. That isn't a jQuery method. So, you have to reach inside of the jQuery object to get a specific DOM element out of it. That's what the [0] does. It reaches into the jQuery object and gets the first DOM element from its internal data structure. Once you have that DOM element, you can then use any DOM element methods on that DOM object.
FYI, if you ever want to get just the first DOM element from a jQuery object, but want the result to be a jQuery object, not just a DOM element, instead of [0], you can use .eq(0) like ths:
$('#Snowsports-row').eq(0).removeClass("hidden");
Now, in this specific case, this is never necessary because $('#Snowsports-row') cannot ever contain more than one DOM element because internally jQuery will only return the first matching DOM element when you are searching for a ID value (since there's never supposed to be more than one matching element with the same ID).
Just keep in mind that DOM element and a jQuery object are completely different types of objects with different methods on them. What makes it slightly confusing is that a jQuery object contains an internal list of DOM elements. But, if the object you are operating on is a jQuery object, then you can only call jQuery methods on it. If you reach into the jQuery object and pull out a DOM element, then you can only call DOM methods on it.
First of all, ids must be unique, so if you have more than one #Snowsports-only elements you can experience problems.
In your question, you are mixing jQuery code with pure Javascript code.
This:
if ($('#Snowsports-row')[0].classList.contains("hidden") {
...
}
Means that you get the first instance of #Snowsports-row (remember that is better if there is only one element with this id), but you get the DOM object (pure javascript) with the jQuery selector. You can do the same thing in jQuery like this:
$('#Snowsports-row').hasClass("hidden")
See more:
https://api.jquery.com/hasclass/
https://developer.mozilla.org/es/docs/Web/API/Element/classList
Sure, because you are operating over a list. Now, you're kind of mistaking the jQuery/javascript code. If you would like to use the same line twice you can basically drop jQuery altogether and write something like this:
var el = document.getElementById('Snowsports-row');
if (el.classList.contains('hidden')){
el.classList.remove('hidden');
}
In the first line you're selecting one specific DOM element, whereas in the second line you are selecting ALL elements in the DOM that fit that selector and removing the "hidden" class from all of them. Basically checking whether the element has a class can only be performed over an element (that's why you need to select the index, specifying a given element), but jQuery allows you to remove the class of every element inside a list (hence your second line)
Use jQuery's .eq() function. So:
var el = $('#Snowsports-row').eq(0);
if (el.hasClass("hidden")) {
$(el.removeClass("hidden")
}
There's also no harm in calling removeClass on an element that might not have that class... so:
$('#Snowsports-row').eq(0).removeClass('hidden');
When accessing an array, when is it appropriate to use the .eq() function?
For example, I have...
slides.eq(slidesLength-1).css("z-index", (slidesLength-1));
and later I have...
for(i=0; i<slidesLength-1; i++) {
$(slides[i]).css("left", "-100%");
}
In the first piece of code, the slideshow stops functioning if I don's use the .eq() function. However, the second piece seems to function whether I use the .eq() function or not. Why is this?
slides is not an array. It's a jQuery object. The .eq() method returns you the element at the specified index as a jQuery object.
While jQuery objects may not be arrays, they can pretend to be by having a length property as well as properties corresponding to the indexes. (Since they are not arrays, you can't call methods like .pop(), .forEach(), etc. on them.)
When you do slides[i], you are actually getting the DOM element, not a jQuery object. The $() function turns the DOM element into a jQuery object.
So, when you do slides.eq(1), internally jQuery is doing $(slides[i]).
P.S. Objects, like jQuery objects, that pretend to be arrays are called "array-like objects". If you console.log(slides), it may look like an array. This is just your console trying to make things convenient for you. (See this question for more info: Creating array-like objects in JavaScript)
.eq() is a jQuery method which returns a jQuery object, while accessing by index returns plain DOM element. You should use eq() when you want to use jQuery methods (css() in this case) on the returned selection.
The reason $(slides[i]) works is because you're constructing a jQuery object by passing the plain element to $() constructor.
Your slides variable is not an Array, but a jQuery object.
.eq() returns a jQuery object, eventually empty if index is out of bounds, and a negative index is counted from the end.
.get() returns a DOM Element, or undefined if index is out of bounds, and a negative index is counted from the end.
[] returns a DOM Element, or throw an Error if index is out of bounds.
...
Additionally, jQuery methods let you interact with a set of elements as it was alone. So you if you do:
slides.css("left", "-100%");
It is applied on every matched elements contained in the jQuery object. It is unnecessary to loop over them.
...
Also the preferred way to loop over matched elements is using the each() method:
slides.each(function (i, el) {
var $el = $(el);
});
...
Also it is an established convention to prefix jQuery variables with a $ sign; it let you to easily differentiate DOM elements from jQuery objects. But that's only a matter of taste.
Typically in a case where jQuery fails to find matching elements using its selector the default value is never an exception but rather a lack of action.
My understanding is this is done by design to ensure that the lack of an element does not result in an error condition. However I have found that jQuery.val() does not exhibit this same behaviour. If a selected element does not exist jQuery.val() will return undefined rather than an empty string (which in keeping with the remainder of the framework I would have expected).
So why is jQuery.val() an exception to the rest of the framework and what would be the best way to change this behaviour?
The key here is chainability of jQuery methods. A jQuery method doesn't return undefined when a selector doesn't match anything because it would break the chain. Consider:
$( '#doesntExist' ).addClass( 'foo' ).fadeIn();
If the selector that doesn't match anything would return undefined it would break the chain since undefined doesn't have any methods of its own. Now every method is executed (and do nothing) whether or not the element is found.
.val() on the other hand is different since it's purpose is to return the value of an element. It doesn't chain at all unlike many other jQuery methods, because a method has to return a jQuery object for it to be able to chain. For example, $( '#foo' ).val().addClass( 'bar' ) does not work regardless of whether the element #foo exists or not.
In this light having .val() return an empty string would not make it any more in line with chainable methods, since no other method returns an empty string when the element isn't found either, and returning undefined does not break chainability since the method doesn't chain in the first place.
(By the way, the same is true for every method that returns a value, like .css() and .data().)
Usually it's more useful to know whether the value of an element is empty or whether the element doesn't exist at all, but if you prefer to always get a string back you can add a method of your own:
$.fn.stringVal = function() {
return( this.val() || '' );
};
If I use .val() to get the value of an item, I expect that item to exist. If it does not, I need to know that. Returning undefined in this case seems the best way.
As pointed out by #Ricardo, .val() performs differently in other cases as well, depending on the input.
jQuery.val() returns the value of an input (or the selected option of a "select")
I'm having trouble with jquery and selectors using the following code:
<div id="test"></div>
console.log($('#test'));
This always returns a list like [<div id="test"></div>] instead of the single element.
This results on always having to write $('#test')[0] for every operations instead of only $('#test'). Any idea on why?
Regards
Jquery will not return the HtmlElement, it returns a jQuery object.
A jQuery object contains a collection
of Document Object Model (DOM)
elements that have been created from
an HTML string or selected from a
document. Since jQuery methods often
use CSS selectors to match elements
from a document, the set of elements
in a jQuery object is often called a
set of "matched elements" or "selected
elements"
The jQuery object itself behaves much
like an array; it has a length
property and the elements in the
object can be accessed by their
numeric indices [0] to [length-1].
Note that a jQuery object is not
actually a Javascript Array object, so
it does not have all the methods of a
true Array object such as join().
http://api.jquery.com/Types/#jQuery
This is an example of the Composite Design Pattern
The Composite Pattern describes a group of objects that can be treated in the same way a single instance of an object can. Implementing this pattern allows you to treat both individual objects and compositions in a uniform manner. In jQuery, when we're accessing or performing actions on a single DOM element or a group of DOM elements, we can treat both in a uniform manner. http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/#designpatternsjquery
jQuery encapsulates any objects found for a number of reasons. For one, it ensures that no matter what, null will never be returned for example. Rather, the elements found are inserted into a list. The fact that even though you're searching for a single element, the mechanism always remains the same and therefore the results will be placed into an array of one element rather than the element itself.
In jQuery it is better to think of selectors as matching multiple items, and your solution would be best if you use the each syntax to iterate through the matches items...
$('#test').each(function() {
console.log($(this));
});
As ID is not unique, jQuery looks for every element with such ID. So it's always returns a list, because threre is no guarantee that the element is exactly one