jQuery .prop() returns undefined, while .attr() works as expected for data-*
That's because there's no data-detail property on HTML element.
Here is a quick explanation for .data(), .prop() and .attr() :
DOM element is an object which has methods
, and properties
(from the DOM
) and attributes
(from the rendered HTML
). Some of those properties
get their initial value
by the attributes
id->id, class->className, title->title, style->style etc.
Consider this element: <input type="checkbox" checked data-detail="somedata" >
The result of the following would be:
$('input').prop('id'); // => " "-empty string, property id exist on the element (defined by DOM) , but is not set.
$('input').attr('id');// => undefined - doesn't exist.
If you do the following:
$('input').attr('id',"someID");
$('input').prop('id'); // => "someID"
$('input').attr('id'); // => "someID"
And also:
$('input').prop('id',"someOtherID");
$('input').prop('id');// => "someOtherID"
$('input').attr('id');// => "someOtherID"
So, some attributes and properties have 1:1 mapping. (change of the attr result change of the prop and vice versa).
Consider the following:
<input type="text" data-detail="somedata" value="someValue">
$('input').prop('value'); // => "someValue"
$('input').val(); // => "someValue"
$('input').attr('value'); // => "someValue"
And if you do:
$('input').prop('value','newVal');
// or
$('input').val('newVal');
$('input').prop('value'); // => "newVal" -value of the property
$('input').val(); // => "newVal" -value of the property
$('input').attr('value'); // => "someValue" -value of the attr didn't change, since in this case it is not 1:1 mapping (change of the prop value doesn't reflect to the attribute value).
Case with the .data()
1) How to get:
- Have in mind that attribute name
is data-*
and property name
is dataset
, so:
<input type="checkbox" data-detail="somedata" >
$('input')[0].dataset; //=> [object DOMStringMap] { detail: "somedata"}
$('input')[0].dataset.detail; // => "somedata"
$('input').prop('dataset'); //=>[object DOMStringMap] { detail: "somedata"}
$('input').prop('dataset').detail; // => "somedata"
$('input').data('detail'); // => "somedata"
$('input').attr('data-detail'); // => "somedata"
2) How to set:
I) $('input').prop('dataset').detail='newData';
$('input').prop('dataset'); //=> [object DOMStringMap] { detail: "newData"}
$('input').prop('dataset').detail; // => "newData"
$('input').attr('data-detail'); // => "newData"
$('input').data('detail'); // => "newData"
II) $('input').attr('data-detail','newData');
$('input').prop('dataset'); //=> [object DOMStringMap] { detail: "newData"}
$('input').prop('dataset').detail; // => "newData"
$('input').attr('data-detail'); // => "newData"
$('input').data('detail'); // => "newData"
So you can see that here is 1:1 mapping, attr change reflects prop and vice versa.
But check the third way:
III) $('input').data('detail','newData');
$('input').prop('dataset'); // => [object DOMStringMap] { detail: "somedata"}
$('input').prop('dataset').detail; // => "somedata"
$('input').attr('data-detail'); // => "somedata"
$('input').data('detail'); // => "newData" <-----******
So, what is happening up here?
$(elem).data(key, value)
does not change theHTML5 data-*
attributes of the element. It stores its values in$.cache
internally.
So for getting data-*
you would never go wrong with .data()
:
$(".saveBtn").on("click", function() {
var saveBtn = $(this);
var detail = saveBtn.data("detail");
var relevantInput = saveBtn.parent().next();
var value = relevantInput.prop("value");
});
Liran H
Updated on July 27, 2022Comments
-
Liran H almost 2 years
I am simply trying to get a couple of properties from two elements. Getting the property
value
from theinput
element works as expected. The problem is with getting the propertydata-detail
property from thebutton
element. It returnsundefined
when using.prop()
, but works as expected when using.attr()
.Can anyone explain this odd behaviour I am witnessing?
HTML
<div class="formRow"> <label for="firstName">First name</label> <div class="detailsControlBtns"> <button id="editFirstName" class="btn ctaBtn greenBtn editBtn">Edit</button> <button class="btn ctaBtn greenBtn saveBtn" data-detail="firstName">Save</button> <button id="closeFirstName" class="btn ctaBtn greyBtn closeBtn">Close</button> </div> <input type="text" id="firstName" name="firstName" value="[+firstName+]" readonly> </div>
JS
$(".saveBtn").on("click", function() { var saveBtn = $(this); // The following statement yields undefined. When using .attr() it works as expected. var detail = saveBtn.prop("data-detail"); var relevantInput = saveBtn.parent().next(); // The following statement works as expected. var value = relevantInput.prop("value"); // ... });
-
Liran H about 8 yearsWow! Thank you for the very detailed answer, I have learned a lot.
-
Arash Ghasemi Rad over 5 yearsThanks, It's more helpful than API's document