jQuery Data vs Attr?
Asked Answered
O

3

547

What is the difference in usage between $.data and $.attr when using data-someAttribute?

My understanding is that $.data is stored within jQuery's $.cache, not the DOM. Therefore, if I want to use $.cache for data storage, I should use $.data. If I want to add HTML5 data-attributes, I should use $.attr("data-attribute", "myCoolValue").

Overpass answered 31/8, 2011 at 18:26 Comment(8)
please read this: forum.jquery.com/topic/when-to-use-attr-vs-dataStubbs
@zzz Except that it doesn't really seem to answer the question...?Baten
Actually it does, indirectly. Attaching an object via attr() can lead to memory leaks (at least in IE), while using data() is safe. He hints at this in his reply though he doesn't explicitly come out and say it. More info on the jQuery docs (see the "Additional Notes"): api.jquery.com/attrJellicoe
@John B, just FYI (even though this is old), the data attribute of data-someAttribute is invalid; per the spec, only lowercase is permitted. You'll run into a myriad of weird issues by using upper-case chars.Jellicoe
@Jellicoe "You'll run into a myriad of weird issues by using upper-case chars" : source pleaseSchroer
@AdrienBe Lot's of references easily found via search, but since I'm bored, here you go: https://mcmap.net/q/66628/-jquery-get-html-5-data-attributes-with-hyphens-and-case-sensitivityJellicoe
@Jellicoe thx for that link, that's very interesting. Also, as mentioned in zzzzBov's answer "HTML attributes are supposed to get ASCII-lowercased automatically" by the browser so using camel case seems rather "dangerous".Schroer
@Jellicoe Thanks for explaining the "why"! It's bugged me for a long time that updating data() doesn't also update the attribute in the DOM, and it was strangely difficult to find an answer as to why.Cyclopentane
B
776

If you are passing data to a DOM element from the server, you should set the data on the element:

<a id="foo" data-foo="bar" href="#">foo!</a>

The data can then be accessed using .data() in jQuery:

console.log( $('#foo').data('foo') );
//outputs "bar"

However when you store data on a DOM node in jQuery using data, the variables are stored on the node object. This is to accommodate complex objects and references as storing the data on the node element as an attribute will only accommodate string values.

Continuing my example from above:
$('#foo').data('foo', 'baz');

console.log( $('#foo').attr('data-foo') );
//outputs "bar" as the attribute was never changed

console.log( $('#foo').data('foo') );
//outputs "baz" as the value has been updated on the object

Also, the naming convention for data attributes has a bit of a hidden "gotcha":

HTML:
<a id="bar" data-foo-bar-baz="fizz-buzz" href="#">fizz buzz!</a>
JS:
console.log( $('#bar').data('fooBarBaz') );
//outputs "fizz-buzz" as hyphens are automatically camelCase'd

The hyphenated key will still work:

HTML:
<a id="bar" data-foo-bar-baz="fizz-buzz" href="#">fizz buzz!</a>
JS:
console.log( $('#bar').data('foo-bar-baz') );
//still outputs "fizz-buzz"

However the object returned by .data() will not have the hyphenated key set:

$('#bar').data().fooBarBaz; //works
$('#bar').data()['fooBarBaz']; //works
$('#bar').data()['foo-bar-baz']; //does not work

It's for this reason I suggest avoiding the hyphenated key in javascript.

For HTML, keep using the hyphenated form. HTML attributes are supposed to get ASCII-lowercased automatically, so <div data-foobar></div>, <DIV DATA-FOOBAR></DIV>, and <dIv DaTa-FoObAr></DiV> are supposed to be treated as identical, but for the best compatibility the lower case form should be preferred.

The .data() method will also perform some basic auto-casting if the value matches a recognized pattern:

HTML:
<a id="foo"
    href="#"
    data-str="bar"
    data-bool="true"
    data-num="15"
    data-json='{"fizz":["buzz"]}'>foo!</a>
JS:
$('#foo').data('str');  //`"bar"`
$('#foo').data('bool'); //`true`
$('#foo').data('num');  //`15`
$('#foo').data('json'); //`{fizz:['buzz']}`

This auto-casting ability is very convenient for instantiating widgets & plugins:

$('.widget').each(function () {
    $(this).widget($(this).data());
    //-or-
    $(this).widget($(this).data('widget'));
});

If you absolutely must have the original value as a string, then you'll need to use .attr():

HTML:
<a id="foo" href="#" data-color="ABC123"></a>
<a id="bar" href="#" data-color="654321"></a>
JS:
$('#foo').data('color').length; //6
$('#bar').data('color').length; //undefined, length isn't a property of numbers

$('#foo').attr('data-color').length; //6
$('#bar').attr('data-color').length; //6

This was a contrived example. For storing color values, I used to use numeric hex notation (i.e. 0xABC123), but it's worth noting that hex was parsed incorrectly in jQuery versions before 1.7.2, and is no longer parsed into a Number as of jQuery 1.8 rc 1.

jQuery 1.8 rc 1 changed the behavior of auto-casting. Before, any format that was a valid representation of a Number would be cast to Number. Now, values that are numeric are only auto-cast if their representation stays the same. This is best illustrated with an example.

HTML:
<a id="foo"
    href="#"
    data-int="1000"
    data-decimal="1000.00"
    data-scientific="1e3"
    data-hex="0x03e8">foo!</a>
JS:
                              // pre 1.8    post 1.8
$('#foo').data('int');        //    1000        1000
$('#foo').data('decimal');    //    1000   "1000.00"
$('#foo').data('scientific'); //    1000       "1e3"
$('#foo').data('hex');        //    1000     "0x03e8"

If you plan on using alternative numeric syntaxes to access numeric values, be sure to cast the value to a Number first, such as with a unary + operator.

JS (cont.):
+$('#foo').data('hex'); // 1000
Berke answered 31/8, 2011 at 19:36 Comment(6)
you can also use $('#bar').data('foo-bar-baz') and it will also work, thoughKrucik
@vitorbal, while this is true, the object returned by .data() will not have the hyphenated form set, so $('#bar').data('foo-bar-baz') will work, but $('#bar').data()['foo-bar-baz'] will not. It's for this reason that I suggest that people avoid using the hyphenated form.Berke
ok, now I see what you mean. Didn't know about that small detail, thanks for the update :)Krucik
@SableFoste, which link? api.jquery.com/data is the correct link for the method, and has not changed as far as I'm aware.Berke
@zzzzBov, sorry, you are correct. It wasn't loading for me last night, while the link I included was. I stand corrected.Contrabassoon
Also data attributes can be cachedOzuna
K
129

The main difference between the two is where it is stored and how it is accessed.

$.fn.attr stores the information directly on the element in attributes which are publicly visible upon inspection, and also which are available from the element's native API.

$.fn.data stores the information in a ridiculously obscure place. It is located in a closed over local variable called data_user which is an instance of a locally defined function Data. This variable is not accessible from outside of jQuery directly.

Data set with attr()

  • accessible from $(element).attr('data-name')
  • accessible from element.getAttribute('data-name'),
  • if the value was in the form of data-name also accessible from $(element).data(name) and element.dataset['name'] and element.dataset.name
  • visible on the element upon inspection
  • cannot be objects

Data set with .data()

  • accessible only from .data(name)
  • not accessible from .attr() or anywhere else
  • not publicly visible on the element upon inspection
  • can be objects
Karakoram answered 27/4, 2015 at 23:2 Comment(4)
Yeah, my main question was where this data was stored, so thanks for that info!Afteryears
Also .attr()is the way to go, if afterwards you want to use the data as selector (.data() will not be found; see codepen.io/anon/pen/EvawPV?editors=1011)Cerography
The fact that the values are stored by Jquery in a way that can only be accessed locally is an advantage when using .data () to manage dynamic values in the page, avoiding the problem that they can be modified by the browser inspector.Nucleolated
@LorenzoMagon - Even locally stored values can be modified by the browser inspector. There is nothing that the browser inspector cannot affect during runtime.Karakoram
G
4

You can use data-* attribute to embed custom data. The data-* attributes gives us the ability to embed custom data attributes on all HTML elements.

jQuery .data() method allows you to get/set data of any type to DOM elements in a way that is safe from circular references and therefore from memory leaks.

jQuery .attr() method get/set attribute value for only the first element in the matched set.

Example:

<span id="test" title="foo" data-kind="primary">foo</span>

$("#test").attr("title");
$("#test").attr("data-kind");
$("#test").data("kind");
$("#test").data("value", "bar");
Girvin answered 28/3, 2019 at 9:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.