How can a javascript Array be stored in an HTML5 data attribute?
I've tried every variation of JSON.stringifycation and escaping characters.
What is the precise method to store the array and retrieve it again?
note
I build the array with [ $("#firstSelectedElement").val(), $("#secondSelectedElement").val() ]. I retrieve id="storageElement" data-storeIt="stuff" with $("#storageElement").data('storeit').
I can never seem to retrieve the data as a true Array, only an Array of characters.
It turned out that you could use the html escaped characters in the element data attribute to have json-like array (encoded are quotes):
<div id="demo" data-stuff='["some", "string", "here"]'></div>
And then in javascript get it without any additional magic:
var ar = $('#demo').data('stuff');
Check this fiddle out.
Edited (2017)
You don't need to use html escaped characters in the data attribute.
<div id="demo" data-stuff='["some", "string", "here"]'></div>
Check this new fiddle out.
It depends on what type of data you're storing in the array. If it's just strings (as it appears to be) and you have a character that you know will never be a part of your data (like the comma in my example below) then I would forget about JSON serialization and just use string.split:
<div id="storageElement" data-storeIt="stuff,more stuff"></div>
Then when retrieving:
var storedArray = $("#storageElement").data("storeIt").split(",");
It will handle a bit better than using JSON. It uses less characters and is less "expensive" than JSON.parse.
But, if you must, your JSON implementation would look something like this:
<div id="storageElement" data-storeIt='["hello","world"]'></div>
And to retrieve:
var storedArray = JSON.parse($("#storageElement").data("storeIt"));
Notice that in this example we had to use semi-quotes (') around the data-storeIt property. This is because the JSON syntax requires us to use quotes around the strings in its data.
The HTML5 data attribute can store only strings, so if you want to store an array you will need to serialize it. JSON will work and it looks like you're on the right path. You just need to use JSON.parse() once you retrieve the serialized data:
var retrieved_string = $("#storageElement").data('storeit');
var retrieved_array = JSON.parse(retrieved_string);
Reviewing the api documentation, jQuery should try to automatically convert a JSON encoded string provided it is properly encoded. Can you give an example of the value you are storing?
Also note that HTML5 data attribute and jQuery .data() methods are two distinct things. They interact, but jQuery is more powerful and can store any data type. You could just store a javascript array directly using jQuery without serializing it. But if you need to have it in the markup itself as an HTML5 data attribute, then you are limited only to strings.
For the record, it didn't work with encoded entities for me, but seems that in order to be parsed as an object, the data attribute must be a well formed JSON object.
So I was able to use an object with:
data-myarray="{"key": "value"}"
or maybe just use single quotes:
data-myobject='{"key1": "value1", "key2": value2}'
Time to have fun! :D
You can store any object into node like that:
$('#storageElement').data('my-array', ['a', 'b', 'c']);
var myArray = $('#storageElement').data('my-array');
If you need nested arrays or just another way to do it. This works:
$('[data-example]').each(function (i, e) {
var json = $(e).data('example');
for(var index in json){
console.log(json[index]["name"] + "=" + json[index]["value"]);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-example='[{"name": "A", "value": 1}, {"name": "B", "value": 2}]' />
<div data-example='[{"name": "C", "value": 3}, {"name": "D", "value": 4}]' />
as suggested by Ulysse BN
Or with eval() that is a dangerous solution as pointed by Bonifacius Sarumpaet but works
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-example="[['A', 1], ['B', 2]]" />
<div data-example="[['C', 3], ['D', 4]]" />
<script>
$('[data-example]').each(function (i, e) {
var arrayFromText = eval($(e).data('example'));
console.log(arrayFromText[0][0] + "=" + arrayFromText[0][1]);
console.log(arrayFromText[1][0] + "=" + arrayFromText[1][1]);
});
</script>
If using PHP do in PHP:
$arr_test = ['A','C','E'];
$coded = json_encode($arr_test);
// paste coded in data-atribute
print '<div class="funPlus" data-arr_diensten="'. $coded . '"></div>';
The HTML on inspect looks like:
<div class="funPlus" data-arr_diensten="["A","C","E"]"></div>
Now in javascript retrieve the array, but if it has only one value it returns as a string. So you have to test and fix this. If it is a string we have to remove the extra quotes. $(this) has to point to the object.
var arr_diensten = $(this).data("arr_diensten");
if (typeof arr_diensten == "string") arr_diensten = [arr_diensten.slice(1, -1)];
console.log(arr_diensten);
Related
I was testing out the data() method of jQuery which seems to be very powerful. This is actually for testing out a fixture I'm going to be making for a unit test (that parses out JSON elements by replacing the single quotes with double quotes).
var test = $('#test');
console.log(test.data('table[data-table-values]'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values="'{'header': ['value1', 'value2']}'"></table>
It returns undefined. However from my understanding this should be returning what the selector is, which in this case should be: '{'header': ['value1', 'value2']}'
Am I missing something?
edit: For reference I am testing against a function that does this:
function parseStuff(str) {
return JSON.parse(
str
.substring(1, (str.length - 1))
.replace(/'/g, '"')
);
}
but the thing is, whats getting passed to is in controller/container (My Rails knowledge is limited so im going on what I can read). but for example some of the code looks like:
<instance of container/controller>.data('tableValues')
where 'tableValues is defined as a selector earlier on in the code, and the instance of container/controller is probably the table object itself I'd assume:
tableValues: 'table[data-table-options]' //A bunch more of these selectors are defined
So essentially im trying to set up a HTML fixture I can test this against. The HTML I posted was how it appears in chrome dev tools (obviously with a lot more stuff in the table element, but im just focusing on this selector in particular)
Retrieving data-* value
You refer to the attribute as table[data-table-values], which is incorrect on two accounts:
table[] is not necessary. I'm not sure why you were using that. This isn't a selector, this is a property lookup.
data-table-values should be table-values. Your HTML attribute is called "data-table-values", but the .data() lookup does not need that for any of the HTML data-* attributes.
The end result of both of these is to have .data('table-values') as evidenced in the example at the bottom.
If you wanted to look up the actual attribute value, then you would need to include the data- prefix, because you're searching for that specific HTML attribute; e.g., $test.attr('data-table-values'), but it's against common practice to do this for data-* attributes.
One thing you should note about the .data() method is that, it operates in memory. It doesn't update your HTML. If you use any sort of inspector you would see that setting $test.data('foo','bar'), it does not bind a foo attribute to the element, nor modifies the DOM, it manages the value internally to jQuery.
Fixing JSON
To use the value as JSON, you need to store it as wellformed JSON, right now you're using single quotes as the encapsulating JSON string delimiter '{'':[]}' and also to delimit the object keys. You must use double quotes for valid JSON.
In the example below, I trim off your leading and ending single quotes (') and then replace all the single quotes around the keys with double quotes ". I broke this into several lines for clarity, but could be condensed into several lines.
Note: if the JSON is valid and properly stored in the data-* attribute, then the client wouldn't need to do so much work scrubbing it and the code would be much more simpler
var $test = $('#test');
var str = $test.data('table-values'); // <=== was:"table[data-table-values]"
console.log('data-* value:', str);
// format to a valid JSON string
str = str.replace(/^'+/, ''); // remove leading single quote
str = str.replace(/'+$/, ''); // remove ending single quote
str = str.replace(/'/g, '"'); // use double quotes
console.log('Replaced single quotes:', str);
// make JS object
var obj = JSON.parse(str);
console.log('obj:', obj);
console.log('obj.header[1]:', obj.header[1]);
// make JSON string
console.log('JSON:', JSON.stringify(obj));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values="'{'header': ['value1', 'value2']}'"></table>
Better HTML
Here is an example per #guest271314's suggestion, which demonstrates having well-formed JSON in your HTML.
Notice there are far fewer lines (only one required to get the JSON object). Provided is the jQuery and the ES6 equivalent:
// jQuery
var obj = $('#test').data('table-values');
console.log('obj:', obj);
console.log('obj.header[1]:', obj.header[1]);
console.log('JSON.stringify(obj):', JSON.stringify(obj));
// ES6
var obj2 = JSON.parse(document.querySelector('#test').dataset['tableValues']);
console.log('obj2:', obj2);
console.log('obj2.header[1]:', obj2.header[1]);
console.log('JSON.stringify(obj2):', JSON.stringify(obj2));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values='{"header": ["value1", "value2"]}'></table>
The issue is because you need to provide the attribute name, minus the data- prefix, to the data() method, not the element selector. Try this:
var $test = $('#test');
console.log($test.data('table-values'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values="'{'header': ['value1', 'value2']}'"></table>
Also note that if you provide the attribute as HTML encoded JSON then jQuery will automatically deserialise it for you so that you can immediately work with the object's properties:
var $test = $('#test');
var obj = $test.data('table-values')
console.log(obj);
console.log(obj.header[0]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="test" data-table-values="{"header": ["value1","value2"]}"></table>
This is a basic question in JavaScript. I tried a lot playing around this, but i can't the solution.
I have an array.
var keys = ["a", "b", "c"];
var array =[];
I am looping this keys to form another array
for (var i =0; i<keys.length; i++){
array[i]= "x" + keys[i];
}
If i print this array
i got ['xa']; but what i needed is ["xa"]
only difference is the quotes ""..
Why because i have to use this array in another json as with double quotes. Thanks in advance..
consider my json array name as final,
var query = {
"_source": {
"include": final
}.
NOw here the query is forming like
var query = {
"_source": {
"include": '["xa"]'
}
But i need:
var query = {
"_source": {
"include": ["xa"]
}
I think you are confused about what you are seeing printed in your console. Strings don't inherently have either single or double quotes associated with them. So, it doesn't matter if your browser displays it as ['a','b','c'] or ["a","b","c"]. The array still contains the same thing. What you DO care about is how it is converted into a string, as you stated in your question. You said you need it to use double quotes. Try using JSON.stringify(). You will notice that this outputs a string in the format you want. Here is a short example:
var myArray = ['a', 'b', "c"];
// notice I even used a mix of single and double quotes in the declaration
var arrayAsString = JSON.stringify(myArray);
console.log(arrayAsString);
The output will be:
["a","b","c"]
If you can pass just through via json it mustn't be problem but if you first read it as a string and after you use that string as an argument, you can use replace function. You can do it as I gave here.
How to replace all occurrences of a string in JavaScript?
Use single quotes and put double quotes inside of it.
array[i]= '"x' + keys[i] + '"';
Is there a way to parse NON wellformed JSON, other than using eval?
The background is, that I'm using data tag values to draw a graph like this:
<div id="data" data-idata="[1,2,3]" data-sdata="['foo','bar','baz']"></div>
This works flawlessly with numeric values, these values are delivered as an array directly in jQuery data, no need to parse JSON here.
However, for the labels a string array is to be passed. eval can parse the string in sdata just fine, but JSON.parse and jQuery.parseJSON fail, because it's not wellformed JSON.
var $data = $("#data").data(),
values;
// use eval
out("#out", eval($data.sdata)); // works...
// use JSON.parse
try
{
values = JSON.parse($data.sdata);
} catch(e) {
// silent catch
}
out("#out1", values); // values is undefined
I put together a JsFiddle here to check the thing.
You get error because ['foo','bar','baz'] contains single-quotation marks. JSON RFC specifies that string should be enclosed in double-quotation marks.
There could be a few work-arounds.
Switch quotation marks in the data- attributes:
<tag data-sdata='["foo","bar","baz"]' />
Or replace in Javascript:
values = JSON.parse($data.sdata.replace("'","\""));
You don't need to parse. Simply use .data(), the function does it for you.
I have changed your HTML, I have swapped quotes in line data-sdata="['foo', 'bar', 'baz']" as JSON should use in double-quotation(") marks.
HTML
<div id="data" data-idata="[1,2,3]" data-sdata='["foo", "bar", "baz"]'></div>
Script
out("#out1", $("#data").data('idata'));
out("#out2", $("#data").data('sdata'));
DEMO
Ofcourse you cannot easy parse corrupted data for 100% this goes for any data-formats and not only JSON.
If the reason the data are malformed are always the same you should fix it with some str_find and replacement functions.
If it is irregular you have no real chance except writing a really intelligenz and big algorithm. The best way here would be to try to extract the real raw data out of the corrupted string and build a real JSON string with valid syntax.
Try
html
<div id="data" data-idata="[1,2,3]" data-sdata='["foo","bar","baz"]'></div>
<div id="out1">out1</div>
<div id="out2">out2</div>
js
$(function () {
var out = function (outputId, elem, dataId) {
return $.each(JSON.parse($(elem).get(0).dataset["" + dataId])
, function (index, value) {
$("<ul>").html("<li>" + index + " -> " + value + "</li>")
.appendTo(outputId);
});
};
out("#out1", "#data", "idata");
out("#out2", "#data", "sdata");
});
jsfiddle http://jsfiddle.net/guest271314/4mJBp/
So basically I have this code:
var string = '{name: "bob", height: 4, weight: 145}';
I would like to know if it is possible to convert that string into an object.
so that I can use
string.name, string.height, and string.weight
(I am retrieving the string variable from a database so I cannot just remove the quotes and make it an object in the first place)
eval, as suggested by Igor, will certainly work but is vulnerable to attack.
Instead you could use a library to parse it for you. There are options in the following link:
Eval is evil... So what should I use instead?
It seems that your string is malformed. In order to work with JSON.parse or even jQuery.parseJSON methods, your keys must have speech marks (" ) around them, like so:
var str = '{"name": "bob", "height": 4, "weight": 145}';
var obj = JSON.parse(str);
You can test this by adding console.log(obj); as the final line. Here is my jsFiddle example.
So try to see if you can pull down the data from the server in the format I have suggested and it can then easily be parsed into a JavaScript object.
I would not use string for a variable name, but:
var obj = eval(string);
alert(obj.name);
or you can use jQuery.parseJSON: api.jquery.com/jQuery.parseJSON.
I want to pass an array into a jQuery data attribute on the server side and then retrieve it like so:
var stuff = $('div').data('stuff');
alert(stuff[0]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<div data-stuff="['a','b','c']"></div>
Why does this appear to alert '[' and not 'a' (see JSFiddle link)
JSFiddle Link: http://jsfiddle.net/ktw4v/3/
It's treating your variable as a string, the zeroth element of which is [.
This is happening because your string is not valid JSON, which should use double-quotes as a string delimiter instead of single quotes. You'll then have to use single-quotes to delimit the entire attribute value.
If you fix your quotation marks your original code works (see http://jsfiddle.net/ktw4v/12/)
<div data-stuff='["a","b","c"]'> </div>
var stuff = $('div').data('stuff');
When jQuery sees valid JSON in a data attribute it will automatically unpack it for you.
Declaring it as an attribute means that it is a string.
So stuff[0] would be equivalent to: var myString = "['a','b','c']"; alert(myString[0]);
You need to make it look like this:
<div data-stuff="a,b,c"></div>
var stuff = $('div').data('stuff').split(',');
alert(stuff[0]);
Retraction: jQuery's parsing fails because it didn't meet the rules of parseJSON.
However, I will stand behind my solution. There are aspects of the others that are less than ideal, just as this solution is less than ideal in some ways. All depends on what your paradigms are.
As others have identified the value is treated as string so it is returning "[". Please try this (aaa is the name of the div and I took out the data-stuff):
$(function(){
$.data($("#aaa")[0],"stuff",{"aa":['a','b','c']});
var stuff = $.data($("#aaa")[0],"stuff").aa;
alert(stuff[0]); //returns "a"
});
A different approach is posted at jsfiddle; var stuff = $('div').data('stuff'); stuff is a string with 0th character as '['
Well, var stuff = eval($('div').data('stuff')); should get you an array