This question already has answers here:
How can I test if two jQuery wrapped DOM elements are the same? [duplicate]
(3 answers)
Closed 7 years ago.
var a=$('#start > div:last-child');
var b=$('#start > div.live')[0];
alert(a==b)
alert(a==$(b))
It's always false. How can you compare two elements in jQuery?
thanks
For the record, jQuery has an is() function for this:
a.is(b)
Note that a is already a jQuery instance.
You could compare DOM elements. Remember that jQuery selectors return arrays which will never be equal in the sense of reference equality.
Assuming:
<div id="a" class="a"></div>
this:
$('div.a')[0] == $('div#a')[0]
returns true.
Every time you call the jQuery() function, a new object is created and returned. So even equality checks on the same selectors will fail.
<div id="a">test</div>
$('#a') == $('#a') // false
The resulting jQuery object contains an array of matching elements, which are basically native DOM objects like HTMLDivElement that always refer to the same object, so you should check those for equality using the array index as Darin suggested.
$('#a')[0] == $('#a')[0] // true
a.is(b)
and to check if they are not equal use
!a.is(b)
as for
$b = $('#a')
....
$('#a')[0] == $b[0] // not always true
maybe class added to the element or removed from it after the first assignment
Random AirCoded example of testing "set equality" in jQuery:
$.fn.isEqual = function($otherSet) {
if (this === $otherSet) return true;
if (this.length != $otherSet.length) return false;
var ret = true;
this.each(function(idx) {
if (this !== $otherSet[idx]) {
ret = false; return false;
}
});
return ret;
};
var a=$('#start > div:last-child');
var b=$('#start > div.live')[0];
console.log($(b).isEqual(a));
The collection results you get back from a jQuery collection do not support set-based comparison. You can use compare the individual members one by one though, there are no utilities for this that I know of in jQuery.
Related
I'm trying to obtain some insight in the context of a jQuery object. I've read a ton of questions on SO, but they all want to fix a specific problem, and the answers thus fix the problem, and didn't really provide me with the knowledge I'm hoping for.
So I have two buttons, and I have a click event that listens for both of them like so:
$('#copyRI, #copyIR').click(function () {...}
Now when I try to establish which element was clicked like so:
$('#copyRI, #copyIR').click(function () {
var test = $(this);
var test2 = $('#copyIR');
var compare = (test === test2);
}
compare returns false when I click the button with id = #copyIR
when debugging I noticed that the context of test and test2 are different:
Now I'm not looking for a way to successfully establish which button was clicked, but I want to obtain some insight in the concept of the "context" in a jQuery object.
Thanks in advance!
When you call $(this) you create a new jQuery object, instantiating it with an HTML Element.
When you call $('#copyIR') you create a new jQuery object, instantiating it with a selector. This stores extra information in the object, including the selector itself.
Even if that wasn't the case, you would be creating two different objects and === (and == for that matter) test if two objects are the same object not if they are identical objects.
$(this) === $(this) would also return false.
If you want to test if the elements are the same, then you can compare the underlying DOM nodes (since those will be the same object)
var compare = (test[0] === test2[0]);
Alternatively, you can just test if the object you have in the first place matches the selector:
var compare = test.is('#copyIR');
You should rather use .is() method here.
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.
CODE:
$('#copyRI, #copyIR').click(function () {
var test = $(this);
var compare = test.is('#copyIR')
}
jQuery contexts (being an Object) are compared by reference, so test === test2 would obviously return false since each variable is pointing to a different jQuery context (the fact that both contexts internally contains a reference to same DOM object doesn't matter).
Try is() instead:
var compare = $(this).is('#copyIR');
See Documetnation
You could simply compare the id.
$('#copyRI, #copyIR').click(function () {
if (this.id === 'copyIR') {
// do something
}
}
I'm looking for a way to do the following:
$("#a" || "#b").val() === ""
as opposed to:
$("#a").val() === "" || $("#b").val() === ""
Any ideas?
Thanks in advance!
For two elements, I believe your example is about as short as you can make it and its meaning is clear. However, if you wish to repeat such logic or evaluate more elements, you might be able to improve upon it by creating a simple function to evaluate if any items in a set match a condition.
Extending jQuery
$.fn.any = function (evaluator) {
var items = $(this);
for (var i = 0; i < items.length; i++) {
if (evaluator(items[i]) === true) {
return true;
}
}
return false;
};
Demo: http://jsfiddle.net/xE76y/1/
This is similar to the Any() method implemented in the .Net LINQ library* (and I'm sure is implemented in other libraries, especially those geared towards functional programming). In c#, you would call such a method:
enumerable.Any( o => o.Value == "" );
JavaScript's syntax (sadly) isn't as concise; you end up with something like:
array.any( function(o){ return o.value === ""; } );
So far, this hasn't saved you anything. However, if you want to iterate over a large number of elements, it becomes much more elegant.
// there could be zero inputs or 100 inputs; it doesn't matter
var result = $("input").any(function (o) {
return o.value === "";
});
Native Solution
Note that we aren't relying on jQuery in our any() method. You could also consider a native JavaScript solution such as the Array.some() method.
some() executes the callback function once for each element present in
the array until it finds one where callback returns a true value. If
such an element is found, some immediately returns true.
Demo: http://jsfiddle.net/xE76y/2/
var result = jQuery.makeArray($("input")).some(function (o) {
return o.value === "";
});
Since this is an array method, it only works on an array. This unfortunately means that document.getElementsByTagName("input").some(...) will not work since getElementsByTagName() returns a NodeList.
Of course, you could push whatever you wanted into an array and call some() on that array. The call to jQuery.makeArray() in the example is just for convenience.
Abstracting the Evaluation Functions
Demo: http://jsfiddle.net/xE76y/3/
Perhaps the evaluation functions (such as testing for an empty string) will be reused. These can be abstracted further.
// ideally, this should NOT be left in global scope
function isEmpty(input) {
return input.value === "";
}
// the check now fits nicely in one line.
if ($("input").any(isEmpty)) {
alert("At least one input is empty.");
}
The resulting method calls are quite clean: $("#a, #b").any(isEmpty) and $("input").any(isEmpty)
* Also worth noting that LINQ has been recreated for JavaScript.
Try like this instead:
if ($('#a,#b').is(':empty'))
{
alert("Either a or b is Empty!");
}
Try my demo
Edit:
If it is an input type like a textbox then it would be a little bit bulky but will achieve the same effect:
if ($.inArray("",[ $("#a").val(), $("#b").val() ])>=0)
{
alert("Either a or b is Empty!");
}
See another Demo
If you want to avoid duplication of the empty string "", you could do this:
if ($.inArray([ $("#a").val(), $("#b").val() ], ""))
Or if you only want to select once with jQuery:
if ($.inArray($("#a, #b").map(function() { return this.value; }), ""))
But I wouldn't use either of these myself. They are arguably both less efficient, more contrived, and certainly less readable than the "easy" way!
I'm not an expert in javaScript, but have you cross checked with :
http://api.jquery.com/multiple-selector/
jQuery selector regular expressions
Also, one way would be using the .each function as in
jQuery Multiple ID selectors
Given the following HTML structure:
<div class="wrap">
<div id="a"></div>
<div id="b"></div>
</div>
the following is false:
($('#a').parent() == $('#b').parent()); //=> false
even though:
$('#a').parent().children('#b').length; //=> 1
Could anyone explain why? Thanks!
I'm not 100% on exactly why it doesn't work, but I believe it is because the elements are wrapped in jQuery objects which are inherently different per element.
As a workaround, you can compare the native DOM object, like this:
($('#a').parent()[0] == $('#b').parent()[0]); // true
Example fiddle
Because of the same reason that $('#a) == $('#a') is false
Each time jQuery builts a set of elements, it returns a new object (even if the jQuery object wraps the same elements as another). In JavaScript, the only time an object is equal to another, is if it's exactly the same object;
var a = {
foo: 1
};
var b = {
foo: 1
};
(a == b) // false;
To fix this, you can either compare the DOM objects directly (either by using .get(i) or using the jQuery object like an array ([i])), or you get use the is() method;
if ($('.foo').get(i) == $('.bar').get(i));
if ($('.foo')[0] == $('.bar')[0]);
if ($('.foo').is($('.bar')); // or even...
if ($('.foo').is('.bar'));
I always wondered why jQuery returns true if I'm trying to find elements by id selector that doesnt exist in the DOM structure.
Like this:
<div id="one">one</div>
<script>
console.log( !!$('#one') ) // prints true
console.log( !!$('#two') ) // is also true! (empty jQuery object)
console.log( !!document.getElementById('two') ) // prints false
</script>
I know I can use !!$('#two').length since length === 0 if the object is empty, but it seems logical to me that a selector would return the element if found, otherwise null (like the native document.getElementById does).
F.ex, this logic can't be done in jQuery:
var div = $('#two') || $('<div id="two"></div>');
Wouldnt it be more logical if the ID selector returned null if not found?
anyone?
This behaviour was chosen because otherwise jQuery would regularly throw NullReference Exceptions
Almost all jQuery functions return a jQuery object as a wrapper around the Dom elements in question, so you can use dot notation.
$("#balloon").css({"color":"red"});
Now imagine $("#balloon") returned null. That means that $("#balloon").css({"color":"red"});
would throw an error, rather than silently doing nothing as you would expect.
Hence, you just gotta use .length or .size().
This is just how jQuery works.
$("#something")
Object 0=div#something length=1 jquery=1.2.6
$("#nothing")
Object length=0 jquery=1.2.6
You can come close to doing what you want by accessing the length the element, and combine with the ternary operator:
console.log(!!$('#notfound').length); // false
console.log(!!$('#exists').length); // true
var element= $('#notfound').length ? $('#notfound') : $('#exists');
console.log(element.attr('id')); // outputs 'exists'
As to the heart of the question:
Wouldnt it be more logical if the ID
selector returned null if not found?
No, not for the JQuery way of doing things - namely, to support chaining of JQuery statements:
$('#notfound').hide("slow", function(){
jQuery(this)
.addClass("done")
.find("span")
.addClass("done")
.end()
.show("slow", function(){
jQuery(this).removeClass("done");
});
});
Even though notfound doesn't exist this code will run without stopping script execution. If the initial selector returns null, you'll have to add in an if/then block to check for the null. If the addClass, find, end and show methods return null, you'll have to add an if/then block to check the return status of each. Chaining is an excellent way to handle program flow in a dynamically typed language like Javascript.
It returns true because to Javascript it is a defined object therefore not false, and jQuery will always give you a new object regardless of whether the element is found or not - however the array length will be zero, e.g.
$("span").length
If you have no <span>, this will be zero, but it could be 1 or more.
You can write your own plugin to avoid repeated if statements as a Jquery plugin, like I did for this one. It's fairly easy to do:
(function($)
{
/* Checks if a jQuery object exists in the DOM, by checking the length of its child elements. */
$.fn.elementExists = function()
{
/// <summary>
/// Checks if a jQuery object exists in the DOM, by checking the length of its child elements.
/// </summary>
/// <returns type="Boolean" />
return jQuery(this).length > 0;
};
})(jQuery);
Usage:
if ($("#someid").elementExists())
{
}
You could check the .length property of the jQuery object. Like this:
if($("#two").length > 0) { // exists...
} else { // doesn't exist
}
In short, you could think of the jQuery selector return value as a group containing 0..n elements, but never being null.
What you're probably really interested in is $("#two")[0], which will give you the first actual element returned by the selector.
This question already has answers here:
How to check if a string "StartsWith" another string?
(18 answers)
Closed 3 years ago.
I know that I can do like ^= to see if an id starts with something, and I tried using that for this, but it didn't work. Basically, I'm retrieving a URL and I want to set a class for an element for path names that start in a certain way.
Example:
var pathname = window.location.pathname; //gives me /sub/1/train/yonks/459087
I want to make sure that for every path that starts with /sub/1, I can set a class for an element:
if (pathname ^= '/sub/1') { //this didn't work...
...
Use stringObject.substring
if (pathname.substring(0, 6) == "/sub/1") {
// ...
}
String.prototype.startsWith = function(needle)
{
return this.indexOf(needle) === 0;
};
You can use string.match() and a regular expression for this too:
if(pathname.match(/^\/sub\/1/)) { // you need to escape the slashes
string.match() will return an array of matching substrings if found, otherwise null.
A little more reusable function:
beginsWith = function(needle, haystack){
return (haystack.substr(0, needle.length) == needle);
}
First, lets extend the string object. Thanks to Ricardo Peres for the prototype, I think using the variable 'string' works better than 'needle' in the context of making it more readable.
String.prototype.beginsWith = function (string) {
return(this.indexOf(string) === 0);
};
Then you use it like this. Caution! Makes the code extremely readable.
var pathname = window.location.pathname;
if (pathname.beginsWith('/sub/1')) {
// Do stuff here
}
Have a look at JavaScript substring() method.