Alex Rivera | Logout

Get list of data-* attributes using javascript / jQuery

Asked 2010-11-15T17:19:32.287
176

Given an arbitrary HTML element with zero or more data-* attributes, how can one retrieve a list of key-value pairs for the data.

E.g. given this:

<div id='prod' data-id='10' data-cat='toy' data-cid='42'>blah</div>

I would like to be able to programmatically retrieve this:

{ "id":10, "cat":"toy", "cid":42 }

Using jQuery (v1.4.3), accessing the individual bits of data using $.data() is simple if the keys are known in advance, but it is not obvious how one can do so with arbitrary sets of data.

I'm looking for a 'simple' jQuery solution if one exists, but would not mind a lower level approach otherwise. I had a go at trying to to parse $('#prod').attributes but my lack of javascript-fu is letting me down.

update

customdata does what I need. However, including a jQuery plugin just for a fraction of its functionality seemed like an overkill.

Eyeballing the source helped me fix my own code (and improved my javascript-fu).

Here's the solution I came up with:

function getDataAttributes(node) {
    var d = {}, 
        re_dataAttr = /^data\-(.+)$/;

    $.each(node.get(0).attributes, function(index, attr) {
        if (re_dataAttr.test(attr.nodeName)) {
            var key = attr.nodeName.match(re_dataAttr)[1];
            d[key] = attr.nodeValue;
        }
    });

    return d;
}

update 2

As demonstrated in the accepted answer, the solution is trivial with jQuery (>=1.4.4). $('#prod').data() would return the required data dict.

Edit
Report

1 Answer

92

A pure JavaScript solution ought to be offered as well, as the solution is not difficult:

var a = [].filter.call(el.attributes, function(at) { return /^data-/.test(at.name); });

This gives an array of attribute objects, which have name and value properties:

if (a.length) {
    var firstAttributeName = a[0].name;
    var firstAttributeValue = a[0].value;
}

Edit: To take it a step further, you can get a dictionary by iterating the attributes and populating a data object:

var data = {};
[].forEach.call(el.attributes, function(attr) {
    if (/^data-/.test(attr.name)) {
        var camelCaseName = attr.name.substr(5).replace(/-(.)/g, function ($0, $1) {
            return $1.toUpperCase();
        });
        data[camelCaseName] = attr.value;
    }
});

You could then access the value of, for example, data-my-value="2" as data.myValue;

jsfiddle.net/3KFYf/33

Edit: If you wanted to set data attributes on your element programmatically from an object, you could:

Object.keys(data).forEach(function(key) {
    var attrName = "data-" + key.replace(/[A-Z]/g, function($0) {
        return "-" + $0.toLowerCase();
    });
    el.setAttribute(attrName, data[key]);
});

jsfiddle.net/3KFYf/34

EDIT: If you are using babel or TypeScript, or coding only for es6 browsers, this is a nice place to use es6 arrow functions, and shorten the code a bit:

var a = [].filter.call(el.attributes, at => /^data-/.test(at.name));
answered 2011-05-06T18:32:07.170

Your Answer