#250 enhancement
arty

Support for .dataset property and data-* attributes

Reported by arty | July 28th, 2008 @ 08:03 PM

Spec of HTML5 describes way to include hidden data in elements via data-* attributes, easily accesible as properties of .dataset property. There's no support for this in browsers, however it's easily emulated:

Element.addMethods({
    getDataset: function(element) {
        if (element.dataset) return element.dataset;
        var match, dataset = {};    
        $A(element.attributes).each(function(attr){
            if (attr.localName.startsWith('data-')) 
                dataset[attr.localName.substring(5)] = attr.nodeValue; 
        });
        return element.dataset = dataset;
    }
});

I believe this may be inclided in core due to very small size and high convenience.

Comments and changes to this ticket

  • John-David Dalton

    John-David Dalton July 28th, 2008 @ 08:53 PM

    • State changed from “new” to “enhancement”

    Can you explain the guts of this method a bit more.

    why is there an need to iterate over all the elements attributes?

  • arty

    arty July 28th, 2008 @ 09:11 PM

    Yes, i think there's such need, as we can't rely on getters/setters yet. Here's simple example of what spec implies:

    <div id="test" data-name="some_internal_name" data-code="bla-bla"></div>
    
    console.log($('test').dataset.name); // "some_internal_name"
    console.log($('test').dataset.code); // "bla-bla"
    console.log($('test').dataset.unexistent); // undefined
    

    So dataset behaves like object, having properties/values filled with data from data-* attributes. Of course, there's another way: create wrapper for accessing these attributes by name, but it doesn't feel right for me, and declines too much from interface described in spec. I know it's optimization time for Prototype team, and tried to optimize method itself.

  • John-David Dalton

    John-David Dalton July 28th, 2008 @ 11:54 PM

    Ahh nice "localName" is a new one for me.

    Thanks I see what you are doing now :)

    I wonder if using

     var attributes = element.attributes;
     for(var i=0, attr; attr = attributes[i]; i++) {
    

    OR

     var attributes = element.attributes, length = attributes.length, attr;
     while (length--) { attr = attributes[length];...
    

    might be faster since it doesn't have to iterate over the list to create an array.

  • arty

    arty July 29th, 2008 @ 09:40 AM

    Yeah, it might be faster, I'm just kinda used to these nice iterators : )

    So here we go:

    Element.addMethods({
        getDataset: function(element) {
            if (element.dataset) return element.dataset;
            var match, attr, dataset = {}, 
                attributes = element.attributes, 
                index = attributes.length;
            while (index--) { 
                attr = attributes[index]; 
                if (attr.localName.startsWith('data-')) 
                dataset[attr.localName.substring(5)] = attr.nodeValue; 
            }
            return element.dataset = dataset;
        }
    });
    
  • Tobie Langel

    Tobie Langel July 30th, 2008 @ 01:58 AM

    If anything, I'd be more in favor of Element#getData and Element#setData. The problem with your current proposal is that you cannot set the attributes that way.

    >>> element.getDataset().foo = "foo";
    "foo"
    >>> element.cloneNode(true).getDataset().foo
    
  • John-David Dalton

    John-David Dalton July 30th, 2008 @ 06:11 AM

    He could set the data in an array like we do with the eventID:

      function getEventID(element) {
        // Event ID is stored as the 0th index in a one-item array so that it
        // won't get copied to a new node when cloneNode is called.
        if (element === window) return 1;
        if (element._prototypeEventID) return element._prototypeEventID[0];
        return (element._prototypeEventID = [arguments.callee.id++])[0];
      }
    
  • arty

    arty July 30th, 2008 @ 10:57 AM

    Actully I thought of this only as of way to embed some data to HTML. Idea that it can be used by JS developers to put data to element with javascript (instead of element._kindaPrivateProperty) didn't came to my head. Now I agree that most probably it would be used that way.

    But one thing which stops me is my dislike for quoted strings as keys (yes, I'm not great fan of Hash#set too). At the moment I'd better live without dataset then use such syntax for it. Need to think more about it.

  • Juriy Zaytsev

    Juriy Zaytsev August 4th, 2008 @ 11:51 PM

    Besides what Tobie said, I see another problem here:

    Manually modifying attributes would not reflect changes in element's dataset (as I assume it should behave in HTML5).

    So, i.e.:

    myElement.getDataset(); // { foo: 'bar' };
    
    // explicitly add attribute
    myElement.writeAttribute({ 'data-baz': 'baz' });
    
    // nothing was changed
    myElement.getDataset(); // { foo: 'bar' }
    

    The method would need to collect proper attributes every time it is run (rather than precaching them as a custom property) to work around this.

  • arty

    arty August 5th, 2008 @ 09:44 AM

    Yeah, I get it. It was my fault that I didn't think of people willing to dynamically modify these attributes. I suggested only one-way data transfer.

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 02:11 AM

    • Tag changed from element to element, section:dom

    [not-tagged:"dom" tagged:"section:dom" bulk edit command]

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 02:12 AM

    • Tag changed from element, section:dom to section:dom

    [not-tagged:"element" bulk edit command]

  • T.J. Crowder

    T.J. Crowder November 16th, 2009 @ 04:50 PM

    [responsible:none bulk edit command]

  • Jason Westbrook

    Jason Westbrook December 21st, 2012 @ 11:32 PM

    • Importance changed from “” to “”

    This pull request has a set/get html5data methods that handle the attributes and the dataset properties correctly

    https://github.com/sstephenson/prototype/pull/84

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป

The Prototype JavaScript library.

Shared Ticket Bins

Pages