简体   繁体   中英

HTML5 nested data-* attributes parsed with Javascript don't return a nested object

I am stuck in a concept of html5 data attributes. That attributes allows nesting like:

<div data-user--name="John" data-user--surname="Doe"></div>

I have seen plugins in the past (like select2 ) and some of them use the following similar syntax to make an AJAX call:

<div data-ajax--url="my/url" data-ajax--method="POST">

This code in background converts to a dataset in javascript and it returns something like this:

data = { 
    ajax: { 
        url: "my/url", 
        method: "POST"
    }
}

But in the practice, vanilla javascript's dataset and jQuery data() methods return different object content.

Javascript

 var el = document.getElementsByTagName("div")[0]; el.innerHTML = "<pre>"+JSON.stringify(el.dataset)+"</pre>";
 <div data-ajax--url="my/url" data-ajax--method="POST"></div>

jQuery 1.x

 $('div').html("<pre>"+JSON.stringify($('div').data())+"</pre>");
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div data-ajax--url="my/url" data-ajax--method="POST"></div>

jQuery 2.x

 $('div').html("<pre>"+JSON.stringify($('div').data())+"</pre>");
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div data-ajax--url="my/url" data-ajax--method="POST"></div>


The code in error seems to be the jQuery 1.x versions, because in 2.x versions jQuery returns the same as vanilla Javascript. I found a related bug so it's confirmed: https://github.com/select2/select2/issues/2969

But I can't find where to construct a nested javascript object with the nested html syntax, like the following example:

{ 
    ajax: { 
       url: "my/url"
       method: "POST"
    }
}

Is there any Javascript method, or a polyfill, that makes this kind of objects reading the data-* HTML attributes? Is it possible to parse the data javascript strings (ie ajax-Method ) and return a nested object ( ajax.method ) ?

Ran into exact same need, but @artofcode's answer parses only 2 levels. So I had to figure out how to parse unlimited number of levels. Here's my solution without limiting levels, based on original answer.

function parseNestedDataSet(data_set) {
    var keys = Object.keys(data_set);
    var data = {};
    for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        var value = data_set[key];
        var splat = key.split('-');

        data = parseNestedDataSetKey(splat, value, data);
    }

    return data;
}

function parseNestedDataSetKey(keys, value, data) {
    data = data || {};
    var key = keys[0].toLowerCase();

    // Not tested, but should convert to camel case
    // var key = keys[0].replace(/-([a-z])/g, function (g) {
    //      return g[1].toUpperCase();
    // });

    if (!data[key]) {
        data[key] = {};
    }

    if (keys.length > 1) {
        keys.splice(0, 1);
        data[key] = parseNestedDataSetKey(keys, value, data[key]);
    } else {
        data[key] = value;
    }

    return data;
}

Didn't test it thoroughly, but it works in my case, like:

  • data-buttons--btn1--title ;
  • data-buttons--btn1--icon ;
  • data-buttons--btn2--title .
function parseDataset(dataset) {
    data = {};
    for(var i = 0; i < Object.keys(dataset).length; i++) {
        var key = Object.keys(dataset)[i];
        var value = dataset[key];
        var splat = key.split("-");
        console.log(key, data, splat);
        if(!data[splat[0]]) {
            data[splat[0]] = {};
        }
        data[splat[0]][splat[1]] = value;
    }
    return data;
}

Untested, but should work. Pass el.dataset into the method, get a data object out like:

data = {
    'ajax': {
        'Method': 'POST',
        'Url': 'my/url'
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM