jQuery Data() Method Associates Data With DOM Elements - SWEET ASS SWEET!

Posted November 20, 2008 at 10:19 AM by Ben Nadel

Tags: Javascript / DHTML, AJAX

I'm sorry that I cannot remember who posted this link, but yesterday on Twitter, someone posted a link to an article titled, "5 Tips for Better jQuery Code." It was a short article with HUGE bomb shell: the jQuery Data() method. I had never seen this jQuery method before, but apparently, it allows you to associate any type of data with a DOM element. This data can, of course, be referenced later using the same keys.

 
 
 
 
 
 
 
 
 
 

When I saw this, it totally blew my mind! I now think back on all the times that I have completely misused REL or ID or TITLE attributes to store critical pieces of data (that were not really REL, ID, or TITLE data respectively). It makes me feel so dirty; there's been this jQuery Data() method sitting there the whole time, doing exactly what I need it to do, and I've just been disrespecting the DOM left and right to achieve my own ends.

As shown in the demonstration above, I set up a small test page to explore the jQuery Data() method. In it, I am basically setting up several links, associating data with them, and then alerting that associated data when the respective link is clicked:

  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <title>jQuery Data() Method</title>
  • <!-- Linked files. -->
  • <script type="text/javascript" src="jquery-1.2.6.min.js"></script>
  • <script type="text/javascript">
  •  
  • // Init page upon DOM load.
  • $(
  • function(){
  • var jLink1 = AddLink( "Kit", 4, "Cute" );
  • var jLink2 = AddLink( "Michelle", 43, "Fun", jLink1 );
  • var jLink3 = AddLink( "Sarah", 3943, "Stubby", jLink2 );
  • var jLink4 = AddLink( "Lori", 23, "Sassy", jLink3 );
  • var jLink5 = AddLink( "Niki", 9, "Angry", jLink4 );
  • }
  • );
  •  
  •  
  • // Add link to DOM.
  • function AddLink( strName, intID, strProperty, jPrevLink ){
  • var jParent = $( "ul:first" );
  • var jListItem = $( "<li></li>" );
  • var jLink = $( "<a>" + strName + "</a>" );
  •  
  • // Associate data with this link.
  • jLink.data(
  • "Data",
  • {
  • Name: strName,
  • ID: intID,
  • Property: strProperty,
  • Prev: jPrevLink
  • }
  • );
  •  
  • // Set link properties.
  • jLink
  • .attr( "href", "javascript:void(0)" )
  • .click( ClickHandler )
  • ;
  •  
  • // Add the link to the list item and then add the
  • // list item to the DOM.
  • jParent.append(
  • jListItem.append( jLink )
  • );
  •  
  • // Return new link.
  • return( jLink );
  • }
  •  
  •  
  • // Handles the link clicks.
  • function ClickHandler( objEvent ){
  • var jThis = $( this );
  •  
  • // Get the property data for this element that was
  • // associated when createing the element.
  • var objData = jThis.data( "Data" );
  •  
  • // Alert data.
  • alert(
  • objData.Name +
  • " is " +
  • objData.Property +
  • (
  • objData.Prev ?
  • "\n\nPrevious Girl: " +
  • objData.Prev.data( "Data" ).Name
  • :
  • ""
  • )
  • );
  •  
  • // Prevent default.
  • objEvent.preventDefault();
  • return( false );
  • }
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • jQuery Data() Method
  • </h1>
  •  
  • <ul>
  • <!-- Data to be added here dynamically. -->
  • </ul>
  •  
  • </body>
  • </html>

In the demo, I am storing all the associated data at a single "Data" index within the associated set. I am not sure if this is considered good or if I should be storing each property individually. Either way, I am just so freakin' pumped up to finally know that this jQuery method exists. This is going to revolutionize the way I build complex AJAX applications.




Reader Comments

Nov 20, 2008 at 10:35 AM // reply »
211 Comments

I posted the link on twitter. I got the link from my google reader. :) Make sure you look into the jquery metadata plugin.


Nov 20, 2008 at 10:39 AM // reply »
11,246 Comments

@Todd,

You rock! You just changed the way I work, my friend... changed the way I work.


Nov 20, 2008 at 10:43 AM // reply »
92 Comments

Only problem that I see with this is that you have to know, in advance, that information is associated with that link, as it otherwise wouldn't be completely obvious to someone jumping into the middle of your code.


Nov 20, 2008 at 10:43 AM // reply »
34 Comments

I second Todd regarding the metadata plugin. The metadata plugin allows you to associate metadata with a DOM element by storing the information in the "class" attribute of the element.

So instead of creating those DOM elements and assigning the metadata to them via a JavaScript iteration, you could create the links and the metadata via a ColdFusion-based iteration and populate the metadata from CF variables.


Nov 20, 2008 at 10:47 AM // reply »
11,246 Comments

@Andy,

I think that's a valid issue to consider. However, I don't think the "behind the scenes" nature of it should cast a shadow on the potential power that this would create. I am thinking in terms of AJAX applications where you might need to create DOM elements that have all sorts of useful properties that would tie into AJAX calls and other events.

@Brian,

I have used CSS classes to create "hooks" such as "save" and "delete" for links and what not. I think one time I stored an ID like:

class="save id:4"

... or something like that. But mostly, I have not used it for data. I will check into this meta data plug-in. Thanks.


Nov 20, 2008 at 10:53 AM // reply »
34 Comments

One thing I forgot to say: the thing I gained from reading that list of tips was learning about the livequery() plugin. I've built a few UIs where the user ends up creating new DOM elements, and having to assign jQuery events to the new element after it's created is a (modest) hassle. Sounds like livequery would solve that problem for me.


Nov 20, 2008 at 10:54 AM // reply »
211 Comments

I posted a sample of metadata's power:
http://pastebin.com/f16fcef56

Let me know if you have questions or if something isn't working. I have this code working right now, but I trimmed out all the CF code and such, so something might be screwy.


Nov 20, 2008 at 10:55 AM // reply »
11,246 Comments

@Brian,

I will have to look into that one a bit more. When I create DOM elements on the fly, they usually all pass through some sort of Init() method that binds all the events. I am not sure if the livequery would do much more than that.


Nov 20, 2008 at 10:56 AM // reply »
11,246 Comments

@Todd,

Thanks man, I'll take a look when I grab a free moment.


Nov 20, 2008 at 10:57 AM // reply »
211 Comments

Yup, just don't forget the jquery.js and metadata.js, I didn't put that in the pastebin code.


Nov 20, 2008 at 11:03 AM // reply »
34 Comments

@Ben: I do a similar thing: any event bindings that need to be done more than once on the page are kept in a separate function. If livequery eliminates the need for me to do that, that's just one less thing to code.


Nov 20, 2008 at 11:09 AM // reply »
11,246 Comments

@Brian,

I see what you're saying. I am definitely going to check it out.


Nov 20, 2008 at 11:47 AM // reply »
20 Comments

I discovered this feature a couple of weeks ago, and it's been a revelation to me!

Hadn't yet got round to blogging it, and now you've beaten me to it...


Nov 20, 2008 at 12:10 PM // reply »
2 Comments

I don't know if you're following me on Twitter or not. I posted a link to the jQuery API doc for .data() the other day just because It does rock.

http://twitter.com/lazycoder/status/1011939872

We've been using it for a while now. I hadn't read that article yet. So this was a great round-about way to find out it.


Nov 20, 2008 at 12:40 PM // reply »
11,246 Comments

@Staicu,

Yeah, you can combine this with any server-side scripting language.

@Scott,

This stuff is awesome :)


Nov 20, 2008 at 2:12 PM // reply »
42 Comments

Seems like .data() is helpful for some small task, but not a replacement for doing MVC in js.

anyone does MVC in js?


Nov 20, 2008 at 2:28 PM // reply »
11,246 Comments

@Henry,

I don't necessarily these two concepts as being conflicting. Even with an MVC architecture, you still need to pass data around with each event. Think about server side request handling - even with MVC where you have an "action" variable, you still need to pass along query string variables (most of the time) along with the action. In the client, you can use this data() method to pass those type of variables around.

Let's look at a really simple example: a dynamic link that has to do something. For arguments sake, let's say that when you click a link, it deletes itself (and a record on the server).

Let's say the links are created as the result of an AJAX call (in which the ID of the target record was passed back). You could do this:

function AddLinkHandler( strID ){
. . . . var jLink = $( "<a>Delete Record" + strID + "</a>" );
. . . .
. . . . // Bind the ID to the link.
. . . . jLink.bind( "id", strID );
. . . .
. . . . // Bind click handler.
. . . . jLink.click( LinkClickHandler );
. . . .
. . . . // Add link to do document.
. . . . AddLinkToDocument( jLink );
}

Now, have a link on the screen that has a click handler and a bound data item. Now, the click handler could be something like this:

function LinkClickHandler( objEvent ){
. . . . var jLink = $( this );
. . . .
. . . . // Delete link on server.
. . . . DeleteRemoteRecord( jLink.data( "id" ) );
. . . .
. . . . // Remove link from document.
. . . . jLink.remove();
. . . .
. . . . // Prevent default.
. . . . objEvent.preventDefault();
}

Now, we have all of our "Requests" going through centralized methods. I believe that this is what MVC is on the client, right? To be honest, I have not worried about MVC on the client much, so I may be way off.

That said, as the request goes through, the data that is bound to the DOM element goes through with it and can then be referenced as part of the request later on (like the query string on a server-side request).


Nov 20, 2008 at 2:55 PM // reply »
42 Comments

I see...

The current solution I have for storing the 'id' of an element is to use the id field of the dom element, (must prepend a string since the id attribute cannot start with numbers).

I can see the benefit of using .data(). I guess using .data() to store metadata like id is a good idea.

However, if the underlying data that the view (i.e. DOM elements) represents is more than a few pieces of metadata, or the app needs to do calculations on the metadata, I think having a real JS model (e.g. array of objects) would be a better way to go. Agree?


Nov 20, 2008 at 3:13 PM // reply »
11,246 Comments

@Henry,

I think I probably agree. I am fairly new to large, client-rich applications, so I'm just feeling my way out in this territory now.

I hear you on just storing the ID in the "id" attribute. I have pulled that move. But I think (in more MVC style goodness), we want to separate the view (HTML) from the data. But, again, I'm really just making guesses at this point since this is all so new and wonderful :)


Nov 20, 2008 at 3:37 PM // reply »
2 Comments

@Henry

Here's one way I use the .data() storage. We often build table rows or add elements dynamically to the page. When we build these things, we give them an id and append a counter (e.g. "UserName_row1_col2"). When can store the appended value in the .data() key like so

newElement.data("suffix","row1_col2");

Then when we write event handlers for the new elements, we can just grab the suffix out of the .data instead of parsing the ID of the element.

//old way
var id = e.target.id.replace("UserName", "");

//new way
var id = "UserName" + $(e.target).data("suffix");

Then we can use the suffix for to find any child elements by id as well.

var suffix = $(parentDiv).data("suffix");
var text = $("#textbox" + suffix).val();
var select = $("#select" + suffix).val();

It may be a personal preference, but when you are dealing with widgets, it makes the event handlers a little cleaner IMO.


Nov 20, 2008 at 5:13 PM // reply »
11,246 Comments

@Scott,

I think it also is going to keep the data much more clear and readable. Thinking about the idea of even having to parse strings to grab mission-critical data? Seems crazy when you can easily pass it through with obvious keys.


Dec 11, 2008 at 9:40 PM // reply »
34 Comments

The other thing is that by not messing with existing HTML attributes you can more easily design unobtrusive code.

for me jQuery's ability to layer on stuff to a functional base means 508 compliance is much easier.


Dec 11, 2008 at 9:42 PM // reply »
34 Comments

The other thing is that by not messing with existing HTML attributes you can more easily design unobtrusive code.

for me jQuery's ability to layer on stuff to a functional base means 508 compliance is much easier.


Dec 11, 2008 at 9:54 PM // reply »
11,246 Comments

@Kevin,

Agreed. Data() is awesome.


Dec 12, 2008 at 8:00 AM // reply »
34 Comments

Found this blog post via the DZone site, where the poster describes how extend jQuery's selector functions so you can actually select DOM elements based on the metadata assigned to the elements via the jQuery data() method:

http://james.padolsey.com/javascript/extending-jquerys-selector-capabilities/

...so, referring back to Ben's code example, you could use this technique to select all of the "Sassy" DOM elements. (Grin) Because we all know we like the sassy page elements the best.


Dec 12, 2008 at 8:03 AM // reply »
11,246 Comments

@Brian,

That is awesome! Thanks for passing that along.


Jul 2, 2009 at 4:58 AM // reply »
2 Comments

Hi Ben

thanks for that cool explenation and sample. I've done a little bit of jquery but seems I've missed a cool part how to use selectors. Sorry for the beginners question, but what does this selectors acutally do here in your sample:
$( "<li></li>" );
$( "<a>" + strName + "</a>" );

what are they 'selectin'? Thanks for your help ;-)
Gerald


Jul 2, 2009 at 9:20 AM // reply »
92 Comments

Gerald...

Those two lines aren't selecting anything. They're creating a new jQuery object that Ben uses later in his code.

You see in the very next line, he does a jLink.data() call. He's storing data in the anchor tag for future reference. Then later he does jListItem.append(jLink) which wraps the anchor tag in the empty list item.


Jul 2, 2009 at 6:13 PM // reply »
2 Comments

Thanks for your quick reply and explanation Andy :-) Hmm, cool, haven't realized that you could actually also create NeW jQuery objects like this. Think I have to play around with it to fully understand how it can be used...

Gerald


Jul 3, 2009 at 8:49 AM // reply »
11,246 Comments

@Gerald,

Correct, and just to further clarify, not only are you creating new jQuery objects, you are creating new HTML elements inside of those jQuery objects. So, the LI and A tags are actually getting created as new DOM elements not currently attached to any tree.


Jul 3, 2009 at 9:29 AM // reply »
2 Comments

cool :-) when/which line actually adds the HTML elements (lets say the "<li></li>")?


Jul 3, 2009 at 9:34 AM // reply »
11,246 Comments

@Gerald,

When you pass HTML to the jQuery factory method ($), it actually creates a DOM element(s) and stores it inside the new jQuery object. So, the line $( "<li></li>" ) creates this jQuery object:

[ <li /> ]

... where the new LI DOM element is the only element in the jQuery "array". To then add the new element to the visible, rendered HTML page, you simply have to inject it with something like this (assuming there is a UL with id, list):

var jLI = $( "<li />" );

$( "#list" ).append( jLI );

Here, we are creating the NEW list element, then finding a reference to the UL element and appending the new list item.


Jul 3, 2009 at 9:51 AM // reply »
2 Comments

Thanks again Ben for explaining. I've got it now and it's been added safely to my gray mass storage ;-)

Take care
Gerald


Jul 3, 2009 at 9:58 AM // reply »
11,246 Comments

@Gerald,

Sweet!


Sep 12, 2009 at 7:00 PM // reply »
1 Comments

You can associate a property set in a separate object structure, but this data feature is way more convenient.

A plug-in that uses the class attribute falls under the category of misusing HTML attributes.


Sep 12, 2009 at 8:25 PM // reply »
11,246 Comments

I just learned from John Resig today that jQuery 1.3.3 will allow us to call the data() method with no arguments to get a full set of the stored data items.


Sep 17, 2009 at 6:40 PM // reply »
5 Comments

I'm working on a project now where the data function of jQuery is proving to be a little buggy in IE (of course). See bug ticket and workaround here:
http://dev.jquery.com/ticket/5265


Sep 18, 2009 at 5:03 PM // reply »
11,246 Comments

@Stephen,

Seems like a funky error. I'm sure they'll get to the bottom of it.


Oct 24, 2009 at 5:02 AM // reply »
1 Comments

Hi Ben, great article / video. I, like you, am blown away that I didn't know this before. Question, how would one use this on new content added to the dom? I have built a calendar app that allows you to click on a jquery datepicker and it loads in the appointments for the day. The appointments for the day are HTML content sent from the server to the calling js function. I guess my question is, is there a way to reset the data method and apply it to new HTML?

Thanks again for the article!


Oct 26, 2009 at 10:12 AM // reply »
5 Comments

Greg, you would use the function the same as with existing DOM elements. Let's say you have some AJAX filling a given DIV with some raw HTML.

In jQuery success function:
$("div.container").html(data);

To apply data to one of its child elements:
$("div.container").find("yourSelector").data("dataName", "dataValue");

Hope that helps!


Oct 31, 2009 at 3:09 PM // reply »
11,246 Comments

@Greg,

@Stephen is right - you can use the data() method on any item in the DOM (or even on non-attached DOM nodes such as those in an intermediary HTML AJAX response). The data() method is not shared by the various nodes; rather, it works on the nodes to store individual pieces of data with any given node.


Oct 31, 2009 at 3:10 PM // reply »
11,246 Comments

@Greg,

If you'd like to see a special kind of demo for this, just let meknow.


Nov 18, 2009 at 1:10 PM // reply »
1 Comments

The "5 Tips Article" Ben mentions in the screencast is Marc Grabanski's awesome http://marcgrabanski.com/article/5-tips-for-better-jquery-code article.


Dec 29, 2009 at 3:50 PM // reply »
1 Comments

This is a sweet bit of video.

If you install FireQuery, the jQuery addon for Firefox & Firebug, you can see the data in the DOM nodes.

FireQuery homepage: http://firequery.binaryage.com/
FireQuery on Firefox Addons: https://addons.mozilla.org/en-US/firefox/addon/12632


Jan 5, 2010 at 8:45 AM // reply »
11,246 Comments

@Sawyer,

Yeah, I have been loving FireQuery. Make is very easy to debug issues that would have otherwise been very difficult.


Jan 9, 2011 at 2:11 PM // reply »
1 Comments

check this:

http://knockoutjs.com/


Feb 21, 2011 at 11:40 AM // reply »
23 Comments

Is there a way to list all text nodes that have a data property? without necessary looping over every text node?

Thanks


Nov 7, 2011 at 6:47 AM // reply »
1 Comments

Only the .data() API reads HTML5 data-* attributes, and it does so once.

The in-memory data object for an element is initialized from those data-* attributes the first time you call .data() for the element. Any subsequent changes to the attributes are ignored, since jQuery has already cached the data.

~ http://www.learningjquery.com/2011/09/using-jquerys-data-apis



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 24, 2013 at 11:21 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, Ha ha, let's us never speak of justifying "##" notation again :P ... read »
May 24, 2013 at 11:18 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Ah, so it was indeed how I vaguely remembered it to be: A direct assignment value = users.id[ i ] causes value to retain the sticky datatype of the query column. Although unnecessary in ... read »
May 24, 2013 at 9:11 AM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Brandon, Hi, No, I haven't been able to do that. I have just kept it as it is. ... read »
May 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools