Create a gist now

Instantly share code, notes, and snippets.

data-* support
(function () {
var forEach = [].forEach,
regex = /^data-(.+)/,
dashChar = /\-([a-z])/ig,
el = document.createElement('div'),
mutationSupported = false,
match
;
function detectMutation() {
mutationSupported = true;
this.removeEventListener('DOMAttrModified', detectMutation, false);
}
function toCamelCase(s) {
return s.replace(dashChar, function (m,l) { return l.toUpperCase(); });
}
function updateDataset() {
var dataset = {};
forEach.call(this.attributes, function(attr) {
if (match = attr.name.match(regex))
dataset[toCamelCase(match[1])] = attr.value;
});
return dataset;
}
// only add support if the browser doesn't support data-* natively
if (el.dataset != undefined) return;
el.addEventListener('DOMAttrModified', detectMutation, false);
el.setAttribute('foo', 'bar');
Element.prototype.__defineGetter__('dataset', mutationSupported
? function () {
if (!this._datasetCache) {
this._datasetCache = updateDataset.call(this);
}
return this._datasetCache;
}
: updateDataset
);
document.addEventListener('DOMAttrModified', function (event) {
delete event.target._datasetCache;
}, false);
})();
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>test data-*</title>
<script src="data.js"></script>
</head>
<body>
<p data-id="ok" data-name="remy" data-screen-name="rem" id="hello">Hello World</p>
<script>
var el = document.getElementById('hello'), dl = el.dataset, a = [], key;
for (key in dl) a.push(key + ': ' + dl[key]);
alert(a.join('\n'));
a.length = 0;
el.setAttribute('data-foo', 'bar');
if (el._datasetCache) alert('Houston: we have a problem!');
dl = el.dataset;
for (key in dl) a.push(key + ': ' + dl[key]);
alert(a.join('\n'));
</script>
</body>
</html>
@remy
Owner
remy commented Apr 29, 2010

Note that setting doesn't work - you have to set this manually on the element via setAttribute. I've not found a way yet that I can define a setter on an unknown property on an object. When the el.dataset object has a property change or updated, it should create a new attribute on the element, but we can't catch that particular update, so it's a no go.

@ThisIsMissEm

Is there any reason not to just use setAttribute and getAttribute (or $.attr through jQuery) ?

@remy
Owner
remy commented Jul 12, 2010

There's no reason not to, I was just coding a proof of concept to show how the final implementation would feel - though in retrospect I realised it's not a complete implementation because I don't handle el.dataset.foo = 'bar', which would then execute el.setAttribute('data-foo', 'bar').

@ThisIsMissEm

hmm, okay, well, for now I'll stick with just using setAttribute / $.attr, as that works. Not to mention
I don't see any benefit from using el.dataset.*, are there any benefits?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment