Milano Slesarik Milano Slesarik - 2 months ago 11
Javascript Question

How to convert HTML data attribute to JSON in JQuery?

I use JSON in hidden element in HTML to avoid multiple unnecessary AJAX requests. JSON is generated properly but I can't handle it using JQuery so I can work with it.

The problem is that

elem.data("json")
returns an object instead of string so
parseJSON
says that there is unexpected o at the start of the string.

$(document).ready(function () {
console.log($('#locations-json').data('json'));
console.log(JSON.parse($('#locations-json').data('json'))); # tried parseJSON
$('.class-destination-from').change(function () {
$.when(get_destination_from_state(),function(res){
//if (res=='city'){
//
//}elif(res=='airport'){
// pass
//}elif(res=='empty'){
// pass
//}
});
})
});


CONSOLE


Object {cities: "[1, 2, 3, 4]", airports: "[5, 6]"} VM1345:1 Uncaught
SyntaxError: Unexpected token o in JSON at position 1


This is the part of HTML:

<div id="locations-json" data-json="{&quot;cities&quot;: &quot;[1, 2, 3, 4]&quot;, &quot;airports&quot;: &quot;[5, 6]&quot;}" style="display: none"></div>


Do you know how to convert it properly?

Answer

The problem, as it so often is, is that data isn't what most people think it is. data is not an accessor for data-* properties, it's both more and less than that. It manages jQuery's internal data cache for the element. It initializes that cache from data-* attributes, but it duplicates the data in the cache, processes the data, and never writes back to the attributes.

It's that "processing the data" that's hitting you in this case: data automatically detects that what you're reading is JSON and parses it for you. So you'll get back an object, and don't need to parse it.

So using data:

var locations = $("#locations-json").data("json");
console.log(locations);
console.log("There are " + locations.cities.length + " cities");
<div id="locations-json" data-json="{&quot;cities&quot;: &quot;[1, 2, 3, 4]&quot;, &quot;airports&quot;: &quot;[5, 6]&quot;}" style="display: none"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

As you noted in a comment, that says there are 12 cities. That's because the JSON gives cities (and airports) a string value:

{"cities": "[1, 2, 3, 4]", "airports": "[5, 6]"}

You probably meant the JSON to be:

{"cities": [1, 2, 3, 4], "airports": [5, 6]}

Example:

var locations = $("#locations-json").data("json");
console.log(locations);
console.log("There are " + locations.cities.length + " cities");
<div id="locations-json" data-json="{&quot;cities&quot;: [1, 2, 3, 4], &quot;airports&quot;: [5, 6]}" style="display: none"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


But unless you need the various features of data, just use attr and parse yourself:

var locations = JSON.parse($("#locations-json").attr("data-json"));
console.log(locations);
console.log("There are " + locations.cities.length + " cities");
<div id="locations-json" data-json="{&quot;cities&quot;: [1, 2, 3, 4], &quot;airports&quot;: [5, 6]}" style="display: none"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


Note:

As of this edit, your question had a valid div that looked like this:

<div id="locations-json" data-json="{&quot;cities&quot;: &quot;[1, 2, 3, 4]&quot;, &quot;airports&quot;: &quot;[5, 6]&quot;}" style="display: none"></div>

But then you edited it again to look like this, which is invalid:

<div id="locations-json" data-json="{"cities": "[1, 2, 3, 4]", "airports": "[5, 6]"}" style="display: none"></div>

The version with &quot; is correct, be sure to use that.