168

I am storing data using the data- approach in a HTML tag like so:

<td><"button class='delete' data-imagename='"+results[i].name+"'>Delete"</button></td>

I am then retrieving the data in a callback like this:

$(this).data('imagename');

That works fine. What I am stuck on is trying to save the object instead of just one of the properties of it. I tried to do this:

<td><button class='delete' data-image='"+results[i]+"'>Delete</button></td>

Then I tried to access the name property like this:

var imageObj = $(this).data('image');
console.log('Image name: '+imageObj.name);

The log tells me undefined. So it seems like I can store simple strings in the data- attributes but I can't store JSON objects...

I've also tried to use this kid of syntax with no luck:

<div data-foobar='{"foo":"bar"}'></div>

Any idea on how to store an actual object in the HTML tag using the data- approach?

AKG
  • 2,936
  • 5
  • 27
  • 36
zumzum
  • 17,984
  • 26
  • 111
  • 172

15 Answers15

184

Actually, your last example:

<div data-foobar='{"foo":"bar"}'></div>

seems to be working well (see http://jsfiddle.net/GlauberRocha/Q6kKU/).

The nice thing is that the string in the data- attribute is automatically converted to a JavaScript object. I don't see any drawback in this approach, on the contrary! One attribute is sufficient to store a whole set of data, ready to use in JavaScript through object properties.

(Note: for the data- attributes to be automatically given the type Object rather than String, you must be careful to write valid JSON, in particular to enclose the key names in double quotes).

  • 27
    If it helps anyone, here's how to access the above: `$('div').data('foobar').foo`. http://api.jquery.com/data/ – Gary Aug 14 '13 at 03:40
  • @GlauberRocha what if you had two elements inside the data-foobar object and you wanted to remove just one element.. how would you do that? – John Ruddell Aug 06 '14 at 14:50
  • Once the data in your markup has been accessed as a javascript object (`var foobar = $('div').data('foobar')`), you can use the **delete** operator to remove a property: `delete foobar.foo` (or `delete foobar['foo']`), or do whatever you like with it. – Nicolas Le Thierry d'Ennequin Sep 10 '14 at 14:08
  • 5
    @GlauberRocha, What if data contains single quote? `'` is not working for me while i `echo json_encode($array)` from php. Since it will terminate attribute value by single quote. Any suggestion except escaping single quote manually from array.? – Ravi Dhoriya ツ Oct 14 '14 at 10:40
  • 1
    @Log1c ツ Just an idea: try encoding your ' as `&quot;` (double-escaped HTML entity) so it's rendered in your source as ". But maybe that's the kind of thing you want to avoid when you say "escaping single quote manually"... – Nicolas Le Thierry d'Ennequin Oct 22 '14 at 08:15
  • 3
    @GlauberRocha thanks for the reply. I solved it using same trick. I used htmlspecialchars()[http://php.net/manual/en/function.htmlspecialchars.php] . It solved. :) – Ravi Dhoriya ツ Oct 22 '14 at 09:54
  • This solution is better because I can set the data trought a server side loop (like a llist in PHP) and alter it after the page loads with jquery dot notation. – Onaiggac Jul 28 '16 at 20:16
  • @RaviDhoriyaツ `htmlspecialchars(json_encode($e))` was perfect, using the jQuery `.data()` later on the field returns the object with all properties! Completely forgot about this, props to you and Nicolas. – CPHPython Jul 11 '18 at 17:07
  • 1
    I ran into trouble using this method when one of the object properties was a string containing a single quote. The data attribute ends at the first single quote encountered and since it isn't valid JSON, it gets interpreted as a string. It might be possible to encode the string, but I found the easiest solution was to just use multiple data attributes. – Jon Hulka Jan 15 '19 at 05:13
  • 2
    single quotes can cause problems, for a future proof solution use the answer mentioned base64 encoding data... – Positivity Mar 17 '19 at 01:10
  • Thanks, man! It's working for me. I have spent a whole day to fix this, hence it is a very simple solution. – Mitesh Rathod Jul 27 '20 at 19:07
160

instead of embedding it in the text just use $('#myElement').data('key',jsonObject);

it won't actually be stored in the html, but if you're using jquery.data, all that is abstracted anyway.

To get the JSON back don't parse it, just call:

var getBackMyJSON = $('#myElement').data('key');

If you are getting [Object Object] instead of direct JSON, just access your JSON by the data key:

var getBackMyJSON = $('#myElement').data('key').key;
nathan gonzalez
  • 11,817
  • 4
  • 41
  • 57
  • 1
    So using the data- approach allows me to store the value for each delete button (each button gets a different json object...) I have in the table by putting in the hmtl tag like I showed above. Is what you're suggesting going to allow me to associate each object with to the corresponding delete button? How would I do that, how would I use $('#myElement'). in the same way? Sorry, I'm not experienced on this. Thanks – zumzum Dec 17 '11 at 06:01
  • So I ended up assigning an index to each html button: , and storing an array of JSON objects in a $objects variable. Then when a button is clicked I look at the button index by doing: var buttonIndex = $(this).data('index'); and then I get the corresponding object from the previously saved like this: $objects[buttonIndex]. This works fine, not sure if it's the correct way of doing it. Thanks for your feedback! – zumzum Dec 17 '11 at 07:35
  • If the field contains the JSON from PHP encoding, you might just want to do this instead: `htmlspecialchars(json_encode($e))` (idea from [Nicolas answer](https://stackoverflow.com/a/9430472/6225838) comments). – CPHPython Jul 11 '18 at 17:10
  • in the first example, does `jsonObject` need to be stringified? edit: in case it helps anyone else, i just found the answer to that question here: https://stackoverflow.com/a/42864472 `"You don't need to stringify objects to store them using jQuery.data()"` – user1063287 Aug 07 '19 at 08:04
80

This is how it worked for me.

Object

var my_object ={"Super Hero":["Iron Man", "Super Man"]};

Set

Encode the stringified object with encodeURIComponent() and set as attribute:

var data_str = encodeURIComponent(JSON.stringify(my_object));
$("div#mydiv").attr("data-hero",data-str);

Get

To get the value as an object, parse the decoded, with decodeURIComponent(), attribute value:

var data_str = $("div#mydiv").attr("data-hero");
var my_object = JSON.parse(decodeURIComponent(data_str));
user1063287
  • 10,265
  • 25
  • 122
  • 218
  • 4
    this seems much more robust than the other options when it comes to handling and escaping quotes – Djave Nov 14 '21 at 16:17
26

A lot of problems with storing serialized data can be solved by converting the serialized string to base64.

A base64 string can be accepted just about anywhere with no fuss.

Take a look at:

The WindowOrWorkerGlobalScope.btoa() method creates a base-64 encoded ASCII string from a String object in which each character in the string is treated as a byte of binary data.

The WindowOrWorkerGlobalScope.atob() function decodes a string of data which has been encoded using base-64 encoding.

Convert to/from as needed.

user1063287
  • 10,265
  • 25
  • 122
  • 218
Dan
  • 1,112
  • 11
  • 14
  • This works really well for passing complex Objects into attributes. – baacke Mar 20 '19 at 13:01
  • 1
    Unfortunately, boot has [Unicode problem](https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings) and is not suitable for all languages. – Ahmad Javadi Nezhad May 04 '19 at 15:56
  • For the browser use `window.btoa` – Henry Aug 30 '19 at 03:09
  • 2
    This method is pretty bulletproof IMO. However, once you retrieve and un-encode your base64 string, you have serialized JSON. So you need touse `JSON.parse` before you can use the result as an object. – Henry Aug 30 '19 at 03:18
  • this is amazing i never knew is was possible thank you so much for sharing! – d0rf47 Nov 18 '21 at 06:37
22

There's a better way of storing JSON in the HTML:

HTML

<script id="some-data" type="application/json">{"param_1": "Value 1", "param_2": "Value 2"}</script>

JavaScript

JSON.parse(document.getElementById('some-data').textContent);
Artur Barseghyan
  • 12,746
  • 4
  • 52
  • 44
16

Combine the use of window.btoa and window.atob together with JSON.stringify and JSON.parse.

- This works for strings containing single quotes

Encoding the data:

var encodedObject = window.btoa(JSON.stringify(dataObject));

Decoding the data:

var dataObject = JSON.parse(window.atob(encodedObject));

Here is an example of how the data is constructed and decoded later with the click event.

Construct the html and encode the data:

var encodedObject = window.btoa(JSON.stringify(dataObject));

"<td>" + "<a class='eventClass' href='#' data-topic='" + encodedObject + "'>" 
+ "Edit</a></td>"

Decode the data in the click event handler:

$("#someElementID").on('click', 'eventClass', function(e) {
            event.preventDefault();
            var encodedObject = e.target.attributes["data-topic"].value;
            var dataObject = JSON.parse(window.atob(encodedObject));

            // use the dataObject["keyName"] 
}
Wayne
  • 3,359
  • 3
  • 30
  • 50
13

For me it work like that, as I need to store it in template...

// Generate HTML
var gridHtml = '<div data-dataObj=\''+JSON.stringify(dataObj).replace(/'/g, "\\'");+'\'></div>';

// Later
var dataObj = $('div').data('dataObj'); // jQuery automatically unescape it
molokoloco
  • 4,504
  • 2
  • 33
  • 27
  • 1
    thanks for sharing..exactly what I was looking for...kept getting [Object Object] when trying to parse the accepted answer. – greaterKing Nov 29 '14 at 03:21
  • @greaterKing you don't parse the JSON from accepted answer, you just access it through the key which is same as the data name so if you have e.g. `$('body').data('myData', { h: "hello", w: "world" })` _____________________________________________________________________________________________ you would get your JSON object by `$('body').data().myData` – jave.web May 21 '15 at 21:08
  • To simplify, you can do `'
    '`. Those are all single quotes, the beginning and end are just escaped, so it would be the same as having `'{"some":"thing"}'`
    – iamface Oct 20 '16 at 18:14
  • 1
    @IamFace - `replace()` addresses the possibility of single quotes appearing in the json data, which is entirely possible. – But those new buttons though.. May 24 '18 at 03:34
3

The trick for me was to add double quotes around keys and values. If you use a PHP function like json_encode will give you a JSON encoded string and an idea how to properly encode yours.

jQuery('#elm-id').data('datakey') will return an object of the string, if the string is properly encoded as json.

As per jQuery documentation: (http://api.jquery.com/jquery.parsejson/)

Passing in a malformed JSON string results in a JavaScript exception being thrown. For example, the following are all invalid JSON strings:

  1. "{test: 1}" (test does not have double quotes around it).
  2. "{'test': 1}" ('test' is using single quotes instead of double quotes).
  3. "'test'" ('test' is using single quotes instead of double quotes).
  4. ".1" (a number must start with a digit; "0.1" would be valid).
  5. "undefined" (undefined cannot be represented in a JSON string; null, however, can be).
  6. "NaN" (NaN cannot be represented in a JSON string; direct representation of Infinity is also n
MarredCheese
  • 17,541
  • 8
  • 92
  • 91
George Donev
  • 563
  • 7
  • 13
0

Using the documented jquery .data(obj) syntax allows you to store an object on the DOM element. Inspecting the element will not show the data- attribute because there is no key specified for the value of the object. However, data within the object can be referenced by key with .data("foo") or the entire object can be returned with .data().

So assuming you set up a loop and result[i] = { name: "image_name" } :

$('.delete')[i].data(results[i]); // => <button class="delete">Delete</delete>
$('.delete')[i].data('name'); // => "image_name"
$('.delete')[i].data(); // => { name: "image_name" }
0

For some reason, the accepted answer worked for me only if being used once on the page, but in my case I was trying to save data on many elements on the page and the data was somehow lost on all except the first element.

As an alternative, I ended up writing the data out to the dom and parsing it back in when needed. Perhaps it's less efficient, but worked well for my purpose because I'm really prototyping data and not writing this for production.

To save the data I used:

$('#myElement').attr('data-key', JSON.stringify(jsonObject));

To then read the data back is the same as the accepted answer, namely:

var getBackMyJSON = $('#myElement').data('key');

Doing it this way also made the data appear in the dom if I were to inspect the element with Chrome's debugger.

Shane E.
  • 85
  • 2
  • 3
0

.data() works perfectly for most cases. The only time I had a problem was when the JSON string itself had a single quote. I could not find any easy way to get past this so resorted to this approach (am using Coldfusion as server language):

    <!DOCTYPE html>
        <html>
            <head>
                <title>
                    Special Chars in Data Attribute
                </title>
                <meta http-equiv="X-UA-Compatible" content="IE=edge">
                <script src="https://code.jquery.com/jquery-1.12.2.min.js"></script>
                <script>
                    $(function(){
                        var o = $("##xxx");
                        /**
                            1. get the data attribute as a string using attr()
                            2. unescape
                            3. convert unescaped string back to object
                            4. set the original data attribute to future calls get it as JSON.
                        */
                        o.data("xxx",jQuery.parseJSON(unescape(o.attr("data-xxx"))));
                        console.log(o.data("xxx")); // this is JSON object.
                    });
                </script>
                <title>
                    Title of the document
                </title>
            </head>
            <body>
                <cfset str = {name:"o'reilly's stuff",code:1}>
<!-- urlencode is a CF function to UTF8 the string, serializeJSON converts object to strin -->
                <div id="xxx" data-xxx='#urlencodedformat(serializejson(str))#'>
                </div>
            </body>
        </html>
Sajjan Sarkar
  • 3,900
  • 5
  • 40
  • 51
0

For the record, I found the following code works. It enables you to retrieve the array from the data tag, push a new element on, and store it back in the data tag in the correct JSON format. The same code can therefore be used again to add further elements to the array if desired. I found that $('#my-data-div').attr('data-namesarray', names_string); correctly stores the array, but $('#my-data-div').data('namesarray', names_string); doesn't work.

<div id="my-data-div" data-namesarray='[]'></div>

var names_array = $('#my-data-div').data('namesarray');
names_array.push("Baz Smith");
var names_string = JSON.stringify(names_array);
$('#my-data-div').attr('data-namesarray', names_string);
Bazley
  • 2,699
  • 5
  • 36
  • 61
0
!DOCTYPE html>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
$("#btn1").click(function()
{
person = new Object();
person.name = "vishal";
person.age =20;
    $("div").data(person);
});
  $("#btn2").click(function()
{
    alert($("div").data("name"));
});

});

</script>
<body>
<button id="btn1">Attach data to div element</button><br>
<button id="btn2">Get data attached to div element</button>
<div></div>
</body>


</html>

Anser:-Attach data to selected elements using an object with name/value pairs.
GET value using object propetis like name,age etc...
0

This code is working fine for me.

Encode data with btoa

let data_str = btoa(JSON.stringify(jsonData));
$("#target_id").attr('data-json', data_str);

And then decode it with atob

let tourData = $(this).data("json");
tourData = atob(tourData);
Hp Sharma
  • 309
  • 3
  • 7
  • Unfortunately, boot has [Unicode problem](https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings) and is not suitable for all languages. – Ahmad Javadi Nezhad May 04 '19 at 15:52
0

I found a better way in https://oblik.dev/utilities/config/ Basically what they do is have a parser from-to json-like objects without double quotes:

import { Parser } from 'oblik/utils/config'

let parser = new Parser()
let result = parser.parse('foo: bar, !baz')
console.log(result) // { foo: "bar", baz: false }

More examples:

<div ob-foo="text: Hello, num: 42">My Foo component</div>

I would like to see something like this format standartized

Chris Panayotoff
  • 1,744
  • 21
  • 24