Over a million developers have joined DZone.

jQuery: Storing and retrieving data related to elements

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

It's very common to need to get information about a DOM element when a user interacts with it -- for example, perhaps you have an unordered list of names, and when a user clicks on a name, you want to show a picture of the person above the list. In order to do this, you need to figure out which person the clicked list item represents. Many beginning jQuery users will attempt to achieve this by putting ID attributes on each list item, such as id="rebecca". Then, they'll read the ID attribute off the clicked element and use it to build a URL for the related image.

  • Paul
  • Rebecca
  • Alex
  • Adam

var portrait = $('#portrait');

$('ul.people li').click(function() {
var name = $(this).attr('id');
portrait.html('');
});
Strictly speaking, this will work. But is the ID really the right place to store this information? What if you need this behavior on other elements on the page too? You can't have more than one element with the same ID on the page, so you might find yourself using funny prefixes in your IDs, like "person_rebecca", and then stripping out the prefix. You could do it with classes, but then you'd have the opposite problem: you're using (generally) unique classes like "rebecca", but really classes are meant to indicate similarities among a set of elements. And what if you need to store more than one piece of information about an element on the element? Next thing you know you've got id="person_alex_red" and you're jumping through all sorts of hoops to parse out the data you need.

Custom Data Attributes

HTML5 makes available custom data attributes, and they prove to be a much more elegant and robust solution to this problem. They're custom, so they can contain pretty much anything you want, and each element can have as many of them as you want.

  • Paul
  • Rebecca
  • Alex
  • Adam

var $portrait = $('#portrait');

$('ul.people li').click(function() {
var $li = $(this),
name = $li.attr('data-name'), color = $li.attr('data-hairColor'),
$img = $('');

$portrait.append($img).css('border', '5px solid ' + color);
});

$.fn.data

When you want to embed information about an element in the HTML you send down from your server, custom data attributes offer a clear and easy solution. But what if you want to attach data to elements that you've added to the page using JavaScript? For example, you might have some data you fetched from your server via an Ajax request:
{
"items" : [
{ "name" : "Paul", "image" : "paul", "hairColor" : "black" },
{ "name" : "Rebecca", "image" : "rebecca", "hairColor" : "brown" },
{ "name" : "Alex", "image" : "alex", "hairColor" : "red" },
{ "name" : "Adam", "image" : "adam", "hairColor" : "red" }
]
}
You're going to iterate over the data to produce a structure much like the one above, but in this case, it doesn't make sense to store the related data in markup, because you'll just have to extract it again later. Instead, you can use the $.fn.data() method in jQuery to store the data using JavaScript instead of markup:
var $target = $('ul.people');

$.each(response.items, function(i, data) {
$('
', { html : data.name }) .data({ name : data.image, hairColor: data.hairColor }) .appendTo($target); }); Later, you can read the data off the element using the $.fn.data() method again, this time passing just the name of the key you're after:
var $portrait = $('#portrait');

$('ul.people li').click(function() {
var $li = $(this),
name = $li.data('name'),
color = $li.data('hairColor'),
$img = $('');

$portrait.append($img).css('border', '5px solid ' + color);
});

Mixing the two methods

This is all well and good, but what if you have a list of people that was sent from the server using HTML and custom data attributes, and then you add elements to it later using JavaScript and store data on them using $.fn.data()? Now your data is stored on elements in two different ways, so how do you extract it reliably? One option is to handle both cases. First, you'll switch to using jQuery's delegate method for the event binding, so you don't have to keep binding click handlers as you add list items to your list. Then, inside of your click handler, you'll figure out where you can get your data from:
var $portrait = $('#portrait');

$('ul.people').delegate('li', 'click', function() {
var $li = $(this), name = $li.attr('data-name'), color, $img;

if (!name) { // did the li have custom data attributes?
name = $li.data('name');
color = $li.data('hairColor');
} else {
color = $li.attr('data-hairColor');
}

$img = $('');
$portrait.append($img).css('border', '5px solid ' + color);
});
Another option is to iterate over the original elements, and store the data from the custom data attributes using the $.fn.data() method:
var $portrait = $('#portrait'), 
$ul = $('ul.people');

$ul.find('li').each(function() {
var $li = $(this);
$li.data({
name : $li.attr('data-name'),
hairColor : $li.attr('data-hairColor')
});
});

$('ul.people').delegate('li', 'click', function() {
var $li = $(this),
name = $li.data('name'),
color = $li.data('hairColor'),
$img = $('');

$portrait.append($img).css('border', '5px solid ' + color);
});

// load more list items via ajax at some point
// to make that whole delegate thing worthwhile
Which option you use will depend on how large your original list is (and thus how long it will take to iterate over it), and how likely people are to click on a lot of items in the list (and thus whether the initial iteration is worth the time). I leave it as an exercise for the reader to decide which approach makes sense for you.

The Metadata Plugin

If you're really into this stuff, you probably also want to check out the jQuery Metadata plugin, which offers the option of reading all custom data attributes on an element and returning an object. So for example, given this markup:

  • Paul
  • You could do:
    var myData = $myListItem.metadata({ type : 'attr' });
    // returns { name : "paul", hairColor : "black" }

    In Conclusion

    When you need to attach data to elements and then extract that data later, there are options beyond classes and IDs, and in fact classes and IDs may be an especially poor way to approach the problem. Taking advantage of custom data attributes and the $.fn.data() method in jQuery can make it painless to store and retrieve data related to elements, and the metadata plugin can streamline the process for you even further.

    Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

    Topics:

    Published at DZone with permission of Rebecca Murphy. See the original article here.

    Opinions expressed by DZone contributors are their own.

    The best of DZone straight to your inbox.

    SEE AN EXAMPLE
    Please provide a valid email address.

    Thanks for subscribing!

    Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
    Subscribe

    {{ parent.title || parent.header.title}}

    {{ parent.tldr }}

    {{ parent.urlSource.name }}