Unable to set data attribute using jQuery Data() API
Solution 1
It is mentioned in the .data()
documentation
The data- attributes are pulled in the first time the data property is accessed and then are no longer accessed or mutated (all data values are then stored internally in jQuery)
This was also covered on Why don't changes to jQuery $.fn.data() update the corresponding html 5 data-* attributes?
The demo on my original answer below doesn't seem to work any more.
Updated answer
Again, from the .data()
documentation
The treatment of attributes with embedded dashes was changed in jQuery 1.6 to conform to the W3C HTML5 specification.
So for <div data-role="page"></div>
the following is true $('div').data('role') === 'page'
I'm fairly sure that $('div').data('data-role')
worked in the past but that doesn't seem to be the case any more. I've created a better showcase which logs to HTML rather than having to open up the Console and added an additional example of the multi-hyphen to camelCase data- attributes conversion.
Also see jQuery Data vs Attr?
HTML
<div id="changeMe" data-key="luke" data-another-key="vader"></div>
<a href="#" id="changeData"></a>
<table id="log">
<tr><th>Setter</th><th>Getter</th><th>Result of calling getter</th><th>Notes</th></tr>
</table>
JavaScript (jQuery 1.6.2+)
var $changeMe = $('#changeMe');
var $log = $('#log');
var logger;
(logger = function(setter, getter, note) {
note = note || '';
eval('$changeMe' + setter);
var result = eval('$changeMe' + getter);
$log.append('<tr><td><code>' + setter + '</code></td><td><code>' + getter + '</code></td><td>' + result + '</td><td>' + note + '</td></tr>');
})('', ".data('key')", "Initial value");
$('#changeData').click(function() {
// set data-key to new value
logger(".data('key', 'leia')", ".data('key')", "expect leia on jQuery node object but DOM stays as luke");
// try and set data-key via .attr and get via some methods
logger(".attr('data-key', 'yoda')", ".data('key')", "expect leia (still) on jQuery object but DOM now yoda");
logger("", ".attr('key')", "expect undefined (no attr <code>key</code>)");
logger("", ".attr('data-key')", "expect yoda in DOM and on jQuery object");
// bonus points
logger('', ".data('data-key')", "expect undefined (cannot get via this method)");
logger(".data('anotherKey')", ".data('anotherKey')", "jQuery 1.6+ get multi hyphen <code>data-another-key</code>");
logger(".data('another-key')", ".data('another-key')", "jQuery < 1.6 get multi hyphen <code>data-another-key</code> (also supported in jQuery 1.6+)");
return false;
});
$('#changeData').click();
Original answer
For this HTML:
<div id="foo" data-helptext="bar"></div>
<a href="#" id="changeData">change data value</a>
and this JavaScript (with jQuery 1.6.2)
console.log($('#foo').data('helptext'));
$('#changeData').click(function() {
$('#foo').data('helptext', 'Testing 123');
// $('#foo').attr('data-helptext', 'Testing 123');
console.log($('#foo').data('data-helptext'));
return false;
});
Using the Chrome DevTools Console to inspect the DOM, the $('#foo').data('helptext', 'Testing 123');
does not update the value as seen in the Console but $('#foo').attr('data-helptext', 'Testing 123');
does.
Solution 2
I was having serious problems with
.data('property', value);
It was not setting the data-property
attribute.
Started using jQuery's .attr()
:
Get the value of an attribute for the first element in the set of matched elements or set one or more attributes for every matched element.
.attr('property', value)
to set the value and
.attr('property')
to retrieve the value.
Now it just works!
Solution 3
@andyb's accepted answer has a small bug. Further to my comment on his post above...
For this HTML:
<div id="foo" data-helptext="bar"></div>
<a href="#" id="changeData">change data value</a>
You need to access the attribute like this:
$('#foo').attr('data-helptext', 'Testing 123');
but the data method like this:
$('#foo').data('helptext', 'Testing 123');
The fix above for the .data() method will prevent "undefined" and the data value will be updated (while the HTML will not)
The point of the "data" attribute is to bind (or "link") a value with the element. Very similar to the onclick="alert('do_something')"
attribute, which binds an action to the element... the text is useless you just want the action to work when they click the element.
Once the data or action is bound to the element, there is usually* no need to update the HTML, only the data or method, since that is what your application (JavaScript) would use. Performance wise, I don't see why you would want to also update the HTML anyway, no one sees the html attribute (except in Firebug or other consoles).
One way you might want to think about it: The HTML (along with attributes) are just text. The data, functions, objects, etc that are used by JavaScript exist on a separate plane. Only when JavaScript is instructed to do so, it will read or update the HTML text, but all the data and functionality you create with JavaScript are acting completely separate from the HTML text/attributes you see in your Firebug (or other) console.
*I put emphasis on usually because if you have a case where you need to preserve and export HTML (e.g. some kind of micro format/data aware text editor) where the HTML will load fresh on another page, then maybe you need the HTML updated too.
Solution 4
Happened the same to me. It turns out that
var data = $("#myObject").data();
gives you a non-writable object. I solved it using:
var data = $.extend({}, $("#myObject").data());
And from then on, data
was a standard, writable JS object.
Solution 5
To quote a quote:
The data- attributes are pulled in the first time the data property is accessed and then are no longer accessed or mutated (all data values are then stored internally in jQuery).
.data()
- jQuery Documentiation
Note that this (Frankly odd) limitation is only withheld to the use of .data()
.
The solution? Use .attr
instead.
Of course, several of you may feel uncomfortable with not using it's dedicated method. Consider the following scenario:
- The 'standard' is updated so that the data- portion of custom attributes is no longer required/is replaced
Common sense - Why would they change an already established attribute like that? Just imagine class
begin renamed to group and id
to identifier. The Internet would break.
And even then, Javascript itself has the ability to fix this - And of course, despite it's infamous incompatibility with HTML, REGEX (And a variety of similar methods) could rapidly rename your attributes to this new-mythical 'standard'.
TL;DR
alert($(targetField).attr("data-helptext"));
Jason Evans
Software developer currently working for Confused.com in Wales, UK. My core skills are .NET C# ASP.NET MVC JavaScript Reputation tracker My Notes http://blogs.microsoft.co.il/blogs/sasha/archive/2009/07/31/garbage-collection-thread-suspension-delay-250ms-multiples.aspx
Updated on October 15, 2020Comments
-
Jason Evans over 3 years
I've got the following field on an MVC view:
@Html.TextBoxFor(model => model.Course.Title, new { data_helptext = "Old Text" })</span>
In a seperate js file, I want to set the
data-helptext
attribute to a string value. Here's my code:alert($(targetField).data("helptext")); $(targetField).data("helptext", "Testing 123");
The
alert()
call works fine, it shows the text "Old Text" in an alert dialog. However, the call to set thedata-helptext
attribute to "Testing 123" does not work. "Old Text" is still the attribute's current value.Am I using the call to data() incorrectly? I've looked this up on the web, and I can't see what I'm doing wrong.
Here's the HTML markup:
<input data-helptext="Old Text" id="Course_Title" name="Course.Title" type="text" value="" />
-
manubkk over 10 yearsNot sure what has changed, but your fiddle demo returns undefined in chrome console
-
ahnbizcad almost 10 yearsSo then what is the point of jQuery allowing you to put in a second argument? To update the value stored in the js variable cache?
-
andyb almost 10 years@gwho I am not sure I completely understand your question, but I assume you are referring to the original answer from 2011 using jQuery 1.6.2. If so, then the .
data('key', 'value')
method does update the value in the jQuery cache but for performance reasons (I guess DOM mutation) the DOM itself is not updated. -
ahnbizcad almost 10 yearsso if you wanted to update the DOM, you'd need to do
.attr('key','value')
regardless of whether you did.data('key', 'value')
or not, right? That seems redundant to me, and I'm having trouble imagining a scenario where you would want to write to the cached DOM, but not the real DOM. Maybe I'm not understand the jQuery cache; So would a visitor see all the things that.data()
modifies on their screen, or would they not? -
andyb almost 10 yearsCorrect, if you really want to update the DOM you need something like
.attr('key', 'value')
or just simplyelement.attributeName = value
. It is jQuery's decision to pull once from the DOM but that doesn't stop you using other methods if you really need the DOMdata-
attributes updating. Don't forget this is about HTML5 custom attributes which are not intended to compete with microformats. You still have access to the updated value in JavaScript where I would expect it to be used. -
ahnbizcad almost 10 yearsSo it's not just a matter of performance; they can't be compared. They have completely different purposes, and they change different "versions" of the DOM. So back to the question: what is the point of using .data() if you have to do .attr() to change the ACUTAL DOM? seems redundant.
-
andyb almost 10 yearsI have always believed it to be solely for performance reasons. this test linked from MDN Using data-* attributes shows a huge performance penalty using
setAttribute
-
Works for a Living almost 10 yearsHow do you then write to it?
-
Nico almost 10 yearsSorry Thom, I don't know what do you mean... After doing
$.extend...
, you can usedata
as you please:data.name = 'Nico'; data.questionSolved = true;
, andconsole.log(data)
will display this newly added properties -
Frank Forte almost 10 yearsthere seems to be a bug:
console.log($('#foo').data('data-helptext'));
should probably be:console.log($('#foo').data('helptext'));
-
andyb almost 10 years@Frankforte that syntax was for the old version of jQuery. I left my original answer since there are multiple ways to get
data-*
attributes using different jQuery versions. -
Buttle Butkus almost 10 yearsDoes this also affect newly-added elements? I cloned a table row that looks like this:
<tr data-id="5"></tr>
, retrieved the id, incremented it, and then used$clone.data('id',new_index)
, and then$tbody.append(clone)
to append the new TR. But the new TR still hasdata-id="5"
. Why wouldn't this work on a newly created element? -
JoeBrockhaus over 9 yearsThis is very frustrating because jQuery's handling of this AND using CSS3's
attr(data-customdata)
breaks the expected HTML5 spec, right? If the only valid custom attributes aredata-
ones, then this valid use casecontent: attr(data-xxx);
will break when using jQuery best practices of setting withjQuery.data()
because the DOM is OOS. -
Matt Komarnicki almost 9 yearsIt's completely weird. I have exactly opposite situation.
$('article#story').data('current', marker_data.id);
works while$('article#story').attr('data-current', marker_data.id);
doesn't behave correctly. :/ -
andyb almost 9 years@slick which version of jQuery are you using? Maybe something changed since I wrote the answer
-
Matt Komarnicki almost 9 years@andyb, jQuery v2.1.1
-
andyb almost 9 years@slick I'll update my demo soon to be a bit smarter but I cannot see any problems with newer jQuery. It's not clear from your comment what is working or not for you. Setting via
.attr
will not update the jQuery object. -
SuperUberDuper over 8 years@JoeBrockhaus so what do you do if your css depends on the Dom changing?
-
JoeBrockhaus over 8 years@SuperUberDuper This was a while ago so my context is limited now, but I think the answer to that you have to know when that is the case, and then in addition to using
jQuery.data()
(which doesn't modify DOM) you have to also update the DOM element attribute so that thecontent: attr(data-xxx);
CSS picks it up. -
Aleks about 8 yearsThanks. This helped, among all other answers with incorrect examples! The
data
inattr('data-helptext'
makes the difference, where the accepted answer and the ones with many votes are not working. +1 -
drooh over 7 yearsFor me I was able to change the data property with data() but I did notice in developer tools it did not show the change, so for that reason I went with attr()