I learned something today thanks to my colleague Axel Hecht; the difference between $element.data('foo')
and $element.attr('data-foo')
.
Basically, the .data()
getter/setter is more powerful since it can do more things. For example:
<img id="image" data-number="42">
// numbers are turned to integers
assert($('#image').data('number') + 1 == 43);
// the more rudimentary way
assert($('#image').attr('data-number') + 1 == '421');
Integers is just one thing the .data()
getter is able to parse. It can do other cool things too like booleans and JSON. Check out its docs
So, why would you NOT use .data()
?
One reason is that with .data(name, value)
the original DOM element is not actually modified. This can cause trouble if other pieces of Javascript depend on the value of a data-
attribute further along in the page rendering process.
To see it in action check out: test.html
In conclusion: just be aware of it. Feel free to use the .data()
getter/setter because it's way better but be aware of the potential risks.
Comments
Post your own commentActually the main difference is that data() is a way to store data for an element. This data is a JS variable. Which means reading from it and writing to it is faster cause it doesn't live in the DOM.
attr() on the other hand is a way to access attributes on nodes.
And it happens that data() will go check if the correspondent data-attribute exists when initialising the value.
Be careful with .data(), it will also convert strings to numbers it shouldn't/can't convert, and silently fail.
If you put a 64-bit integer in a data html-attribute, jQuery will see it as a number (and thus cast it to a number), although Javascript doesn't support 64-bit integers. The result will be a completely different number, without any warning.
An example: If you have a twitter uid, save it in a data-twitter-uid-attribute and fetch that with jQuery.data('twitter-uid'), you'll get a faulty result, because a twitter uid exceeds Javascript's integer size limit.
Yes, the real risk is using attr('data-foo') to read the data. Better to always use .data('foo') to read it.
Check what Jurriaan wrote above. There are risks with reading with .data()
That's depressing (the comment was not visible when I posted). Good to know though. You might want to wrap the logic in your own getData() method should you really never want to directly expect that there is an html attribute. Something along the lines of (untested):
$.fn.getData( function( attr ){
if ( this.attr( 'data-' + attr ) ) {
return this.attr( 'data-' + attr );
}
return this.data( attr );
} );
This way, data could be set on the element as either an attribute or using .data() and you run no risk of expecting either one when you want to read the data back.
Or, indeed, a somewhat tidier version:
$.fn.getData( function( attr ){
return this.attr( 'data-' + attr ) || this.data( attr );
} );
If your data attr held a json object you might want to check first.
function isJson(str) {
try {
JSON.parse(str);
} catch (e) {
return str;
}
return JSON.parse(str);
}
$.fn.getDataAttr = function( attr ){
if ( this.attr( 'data-' + attr ) ) {
return isJson(this.attr( 'data-' + attr ));
}
return this.data( attr );
};
These 2 functions will ensure that you get the data back properly .
Live long and prosper!
You can just stick another parameter onto a node, if you don't need to set it in the html. eg:
node.something = '23skidoo';
node.something
> '23skidoo'
Just don't trample on the stuff that needs to be there.
Great Post. I just saw this behaviour today. Thanks