Why does jQuery.val() behave differently to the rest of jQuery - javascript

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")

Related

How do I check an element is exists in JQuery?

I have to set a specific value to an element if the element is exists.
var a = jQuery("#abc");
if(a) {
a.val("something");
}
For this, I've to check a.length to check the element is exits.
What happen if I directly set the value without checking the element is present or not?
Because, If I do the following
jQuery("#abc").val("dfd");
I don't get any error in chrome when the element is not present. So, can I continue to use like this?
or
any workaround?
Help appreciated!
What happen if I directly set the value without checking the element is present or not?
Nothing. Calling jQuery methods on an empty jQuery object (set) doesn't cause a problem, it just does nothing. This is one of the great things about the set-based concept used in jQuery. The equivalent DOM code (document.getElementById("abc").value = "something";) would throw an error, but the jQuery version doesn't.
Specifically, if the jQuery set is empty:
Calling setter methods (like your val call) becomes a no-op.
Calling getter methods — for instance, var x = $("#foo").val(); — returns the value undefined.
Calling traversal methods — for instance, var divs = $("#foo).find("div"); — gives you a new empty set.
You only need to check (using if (a.length) as you said, or if (a[0])) if you actually care.
jQuery("#abc").val("dfd");
I don't get any error in chrome when the element is not present. So, can I continue to use like this?
Yup.
jQuery's val() method simply sets (or gets) the value of each matching element. If there are no matching element, there will be no value to set (or get). You don't need to check if the element exists first.
From jQuery's val() documentation:
Description: Set the value of each element in the set of matched elements.
If there are no matched elements, nothing will happen.
Try with -
jQuery("#abc").length > 0
Yes, you can safely continue. JQuery just executes a function on all elements found by the selector - if there are none, it does nothing. There's no error.

jQuery API architecture choices: why return single value instead of arrays for attr(), val(), ...?

I am curious about the reasoning behind some of jQuery API architecture choices.
FROM THE DOCUMENTATION
attr():
Get the value of an attribute for the first element in the set of matched elements.
val():
Get the current value of the first element in the set of matched elements.
Even if I have many objects:
$('div').val()
would only return the value of the first element.
But SETTING works differently:
val(value):
Set the value of each element in the set of matched elements.
attr(attributeName, value):
Set one or more attributes for the set of matched elements.
So my questions:
Why decide that getter operations like val() should return only the first value instead of an array of values?
(The user has to use a map operation if he wanted all of them in an array)
Why not do the same with setter operations like .val(value)?
I can see a use case (with $('div').first()) where we expect the call to val() to return the value (we know there is only one dom element in the matched set) instead of an array of length 1. But why not handle it with a concept of a "single dom element query object" (that only gets created after calls to methods like first() or eq())?
Caveat: I do not take part in the jquery development, so these thoughts may be entirely off the actual design decisions.
Anyway, imho your proposal does not seem to offer any advantage:
to process an array of data gleaned from the elements of a jquery collection the user would have to iterate over this array anyway - this can be done using jquery's each method in the first place which has the additional benefit of immediate access to the element carrying the attribute:
$("my_spiffy_selector").each( function ( idx, e ) {
$(e).attr("blarf").whatever();
});
Otoh it would complicate matters (at least the jquery code base), if the getters return type would be polymorphic or if there were different getters.
The arguably most common use case would entail at least an additional .first() call.

Strange ie behaviour with jquery inArray

Hello this seems to be working on IE8 :
var clsName = link.parents("div.fixed_column").attr("class").split(" ");
if($.inArray("column_one", clsName)
While this one reports error (Object expected errror in jquery).
var clsName = link.parents("div.fixed_column").attr("class");
What is the right way to do this? I thought purpose of inArray was that jquery will handle cross browser issues.
Unfortunately, this is indirectly answering your question, but... You seem to be looking to detect if an element has a class, and since you're already using jQuery, just use the hasClass method - http://api.jquery.com/hasClass/
For your specific code, try:
if (link.parents("div.fixed_column").hasClass("column_one")) {
// It has the "column_one" class
}
The more immediate answer to your question is that link.parents("div.fixed_column").attr("class") returns a single string. When the jQuery selector (div.fixed_column) returns multiple elements, which is very possible when using classes, using jQuery methods that get information (like .attr, using one parameter...to "get" the value) return the first matched element's value only.
So say the selector matches 3 elements:
["<div id='div30' class='fixed_column div30_class'></div>",
"<div id='div2' class='fixed_column div2_class'></div>",
"<div id='div17' class='fixed_column div17_class'></div>"]
Then the value returned from .attr("class") will be: fixed_column div30_class because it's the first matched element.
I'm not sure, but I think you're expecting jQuery to return an array of all the matched elements' values, which it just doesn't. So that doesn't mean jQuery isn't handling cross-browser issues, it just means you need to look up what the method does/returns.
I could've sworn that jQuery 2.0 has options for doing what you want - directly from calling the getters (or something similar), but I can't find it anymore :( Maybe I'm remembering incorrectly. Anyways, you could easily use $.each and/or $.map to look at every matched element, but it depends on what you were really trying to do with it.
You can't read the attributes of multiple elements into an array with .attr("class"). But why don't you just target the desired class in the selector like this?
var cols = link.parents("div.fixed_column.column_one");
Then change your conditional to check for an empty set:
if(cols.length) { ...

How can I rewrite jQuery without guard clause?

How can I rewrite this jQuery to be more terse and without the guard clause?
var myTextBox = $('#myTextBox');
if (myTextBox )
myTextBox.val("");
The guard clause is there simply to ensure that the element exists on the page before trying to set it's value but the code seems bloated and most of it unnecessary.
What's the preferred solution to this?
$('#myTextBox').val("") will do nothing if the jQuery object has a length of 0, so simply use it.
Unless you need to cache the selector for future operations, I would do this:
$('#myTextBox').val("")
If there are none selected, nothing will get enumerated, so jQuery will not run the val() routine.
It'll work just as $('#myTextBox').val("");, if it finds no object then it will just be an empty jQuery object and the .val() routine will do nothing.
I believe that if #mytextbox doesn't exist, mytextbox will not be undefined anyway, it will be an empty jQuery object. So the check is redundant.
I also think that if you perform an operation on an empty jQuery object nothing will happen anyway, so you're safe.

Why does $("body") == $("body") return false?

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...

Categories