jQuery's data() attribute does not update when element data changes
Solution 1
The short answer is: don't use jQuery .data() for dynamically set data attributes, unless you can guarantee that data attributes are always set by jQuery.
Either solution below will work:
- Use vanilla JS
.getAttribute()
instead - Use jQuery
.attr()
instead
Here's the relevant part from the jQuery documentation (which I don't think really highlights how much this might surprise jQuery users):
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).
Regarding why you might not use jQuery to set attributes: many client side templating languages build DOM, including data attributes.
Given the dynamically built HTML (as shown in DevTools:
<form data-test="300" ...
DOM API tells the truth:
document.querySelector('form').getAttribute('data-test');
JQuery returns an out-of-date previous value (in this case, 19000):
$('form').data('test');
jQuery attr
returns the current value:
$('form').attr('data-amount');
Vanilla JS getAttribute()
returns the current value:
document.querySelector('form').getAttribute('data-amount');
Solution 2
You can also use jQuery's .removeData() method after updating the data attribute to reset its cache.
For example:
> document.querySelector('.sub-panels')
<div class="sub-panels">…</div>
> document.querySelector('.sub-panels').setAttribute('data-test', 300);
undefined
> document.querySelector('.sub-panels')
<div class="sub-panels" data-test="300">…</div>
> $('.sub-panels').data('test')
300
> document.querySelector('.sub-panels').setAttribute('data-test', 400);
undefined
> $('.sub-panels').data('test')
300
> $('.sub-panels').removeData();
[div.sub-panels, prevObject: jQuery.fn.init(1), context: document, selector: ".sub-panels"]
> $('.sub-panels').data('test')
400
Solution 3
If you are not bound to jQuery, you can use attributes to iterate over all attributes. Then it doesn't matter if they were added dynamically or not.
const p = document.getElementById('test')
p.setAttribute('data-test', 300)
for (const attr of p.attributes) {
// possibly filter with attr.name.startsWith('data-')
console.log(`${attr.name}: ${attr.value} (is data-attr: ${attr.name.startsWith('data-')})`)
}
p.setAttribute('data-new', 400)
for (const attr of p.attributes) {
// possibly filter with attr.name.startsWith('data-')
console.log(`${attr.name}: ${attr.value} (is data-attr: ${attr.name.startsWith('data-')})`)
}
<p id="test">Test</p>
Related videos on Youtube
chaonextdoor
Updated on June 12, 2022Comments
-
chaonextdoor about 2 years
I wanna use jQuery's
data()
api to retrieve all the data attribute of an element. But the cache nature of this api is really annoying. Sometimes I need to change some data atribute of an element in javascript but thedata()
api always return the initial value of each data attribute. So I have to use theattr()
to access each data attribute of an element to get its up-to-date value. Is there any way to overcome this cache thing and makedata()
always return the latest value every time I call it?-
adeneo over 10 yearsIt's not a cache thing,
data()
stores data internally and does not change the data attributes, if you have to change the attribute for some reason you should be usingattr()
, but if you're usingdata()
consistently to both set and get the data it shouldn't be an issue, as you'll get the right data. -
nnnnnn over 10 years"Sometimes I need to change some data atribute of an element in javascript" - Why? If you need to store data against the element after the page loads you can use
.data('key','value')
. This doesn't store the data as an attribute, but so what? -
mikemaccana over 9 years@nnnnnn Every client side templating language ever builds DOM, which may include data attributes, and most likely does not do so with jQuery.
-
-
fmquaglia over 5 yearsGreat answer, sir. Thank you!
-
502_Geek about 4 yearsAbsolutely correct answer. I was trouble a few hours for this issue.