3

Anyone know a quick and efficient way to grab all the data attributes from a single element? I realize that jQuerys .data() will do just that, however it will not give me data attributes set using .attr() UNLESS I first select the data attribute using .data(); Also, you can't select elements by data attributes that were added using .data(), which seems silly.

html

<div data-foo="bar"></div>

javascript

$("div").data();
//returns {foo:bar} good :)

$("div").attr("data-hello","world");
$("div").data()
//returns {foo:bar} no good :(

$("div[data-hello]");
//returns the div, all good :)

$("div").data("find","me");
$("div[data-find]");
//returns nothing, very bad

Hopefully this explains

Rob Proctor
  • 79
  • 1
  • 8

2 Answers2

6

You can use the dataset property in modern browsers(IE11+ only), but you can enhance the solution to use .attributes to support older browsers

var $in = $('input'),
    input = $in[0], //here input is a dom element reference
    dataMap = input.dataset;
//if dataset is not supported
if (typeof dataMap == 'undefined') {
    dataMap = {};
    $.each(input.attributes, function (key, attr) {
        var match = attr.name.match(/^data-(.+)/);
        if (match) {
            dataMap[match[0]] = attr.value;
        }
    })
}
$.each(dataMap, function (key, value) {
    console.log(key, value)
})

Demo: Fiddle

Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
5

Different versions of Internet Explorer support different features that are relevant to this issue. In version 11, support for dataset was added, which returns a DOMStringMap of data-attribute names (minus the "data-" portion), and their respective values.

In versions 9 and 10, we can leverage Array.prototype.slice to convert the well-supported attributes collection into an array that we can then reduce to an object, similar to DOMStringMap.

We can combine both of these approaches into a single function that accepts an element as its argument, and returns an object like this { name: "pat", "age": 23 } for all data- attributes:

function getDataAttributes ( el ) {
    return el.dataset || [].slice.call( el.attributes ).reduce(function ( o, a ) {
        return /^data-/.test( a.name ) && ( o[ a.name.substr( 5 ) ] = a.value ), o;
    }, {} );
}

If you require support for Internet Explorer 8, or below, you can still use the above approaches, and simply polyfill Array.prototype.reduce.

Sampson
  • 265,109
  • 74
  • 539
  • 565