Why do I get an extra element at the end in JSON? - javascript

I'm working on some website, and am using JSON. My problem is the JSON.parse method, I use it to send a simple array, and append to an array the values. And I always get an extra element at the end that us just commas. here is the simplified code:
responseText = '["dummy1", "dummy2", "dummy3", "dummy4"]';
var clientList=[];
try {
JSON.parse(responseText, function(key, val){clientList.push(val)});
} catch (e) {
alert('no');
}
alert(clientList.length);
First in IE its not working at all (exception is thrown).
Second chrome the result is that clientList is an array of 5 strings, while the last one is ',,, '.
Why is that extra value there? Can I get rid of it (without just popping the array at the end)? And what is wrong with IE?

This will work:
responseText = '["dummy1", "dummy2", "dummy3", "dummy4"]';
var clientList=[];
try {
clientList = JSON.parse(responseText);
} catch (e) {
alert('no');
}
IE doesn't have JSON as a default in the browser. You need a library like json2.
As for your question, that callback function is really in order to transform your object not build it. For example:
var transformed =
JSON.parse('{"p": 5}', function(k, v) { if (k === "") return v; return v * 2; });
// transformed is { p: 10 }
From parse

There are differences in using JSON under different browsers. One way is to do what IAbstractDownvoteFactory said. Another way is to use jQuery library and
clientList = $.parseJSON(responseText);
should do the job under any browser (although I did not test it under IE).

Related

Complex JSON obj and jQuery or Javascript map to specific key, value

I am banging my head trying to figure this out. And it should not be this hard. I am obviously missing a step.
I am pulling data from: openaq.org
The object I get back is based on a JSON object.
For now, I am using jQuery to parse the object and I am getting to the sub portion of the object that hold the specific parameter I want but I can't get to the specific key,value pair.
The object does not come back in the same order all the time. So when I tried to originally set up my call I did something like
obj.results.measurements[0].
Well since the obj can come back in an random order, I went back to find the key,value pair again and it was the wrong value, throwing my visual off.
That said, I have looked at use jQuery's find() on JSON object and for some reason can not get what I need from the object I am given by openaq.org.
One version of the object looks like this:
{"meta":{"name":"openaq-api","license":"CC BY 4.0d","website":"https://u50g7n0cbj.execute-api.us-east-1.amazonaws.com/","page":1,"limit":100,"found":1},"results":[{"location":"Metro Lofts","city":null,"country":"US","coordinates":{"latitude":39.731,"longitude":-104.9888},"measurements":[{"parameter":"pm10","value":49.9,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"µg/m³"},{"parameter":"pm1","value":24,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"µg/m³"},{"parameter":"um100","value":0,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"particles/cm³"},{"parameter":"um025","value":0.28,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"particles/cm³"},{"parameter":"um010","value":4.1,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"particles/cm³"},{"parameter":"pm25","value":41.1,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"µg/m³"}]}]}
I am trying to get the "pm25" value.
The code I have tried is this:
function getAirQualityJson(){
$.ajax({
url: 'https://api.openaq.org/v2/latest?coordinates=39.73915,-104.9847',
type: 'GET',
dataType: "json"
// data: data ,
}).done(function(json){
console.log("the json is" + JSON.stringify(json));
console.log("the json internal is" + JSON.stringify(json.results));
var obj = json.results;
var pm25 = "";
//console.log(JSON.stringify(json.results.measurements[0]["parameter"]));
$.each(json.results[0], function(i,items){
//console.log("obj item:" + JSON.stringify(obj[0].measurements));
$.each(obj[0].measurements, function(y,things){
//console.log("each measurement:" + JSON.stringify(obj[0].measurements[0].value));//get each measurement
//pm 2.5
//Can come back in random order, get value from the key "pm25"
// pm25 = JSON.stringify(obj[0].measurements[2].value);
pm25 = JSON.stringify(obj[0].measurements[0].value);
console.log("pm25 is: " + pm25); // not right
});
});
//Trying Grep and map below too. Not working
jQuery.map(obj, function(objThing)
{ console.log("map it 1:" + JSON.stringify(objThing.measurements.parameter));
if(objThing.measurements.parameter === "pm25"){
// return objThing; // or return obj.name, whatever.
console.log("map it:" + objThing);
}else{
console.log("in else for pm25 map");
}
});
jQuery.grep(obj, function(otherObj) {
//return otherObj.parameter === "pm25";
console.log("Grep it" + otherObj.measurements.parameter === "pm25");
});
});
}
getAirQualityJson();
https://jsfiddle.net/7quL0asz/
The loop is running through I as you can see I tried [2] which was the original placement of the 'pm25' value but then it switched up it's spot to the 3rd or 4th spot, so it is unpredictable.
I tried jQuery Grep and Map but it came back undefined or false.
So my question is, how would I parse this to get the 'pm25' key,value. After that, I can get the rest if I need them.
Thank you in advance for all the help.
You can use array#find and optional chaining to do this,
because we are using optional chaining, undefined will be returned if a property is missing.
Demo:
let data = {"meta":{"name":"openaq-api","license":"CC BY 4.0d","website":"https://u50g7n0cbj.execute-api.us-east-1.amazonaws.com/","page":1,"limit":100,"found":1},"results":[{"location":"Metro Lofts","city":null,"country":"US","coordinates":{"latitude":39.731,"longitude":-104.9888},"measurements":[{"parameter":"pm10","value":49.9,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"µg/m³"},{"parameter":"pm1","value":24,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"µg/m³"},{"parameter":"um100","value":0,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"particles/cm³"},{"parameter":"um025","value":0.28,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"particles/cm³"},{"parameter":"um010","value":4.1,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"particles/cm³"},{"parameter":"pm25","value":41.1,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"µg/m³"}]}]}
let found = data?.results?.[0]?.measurements?.find?.(
({ parameter }) => parameter === "pm25"
);
console.log(found);
You can iterate over measurements and find the object you need:
const data = '{"meta":{"name":"openaq-api","license":"CC BY 4.0d","website":"https://u50g7n0cbj.execute-api.us-east-1.amazonaws.com/","page":1,"limit":100,"found":1},"results":[{"location":"Metro Lofts","city":null,"country":"US","coordinates":{"latitude":39.731,"longitude":-104.9888},"measurements":[{"parameter":"pm10","value":49.9,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"µg/m³"},{"parameter":"pm1","value":24,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"µg/m³"},{"parameter":"um100","value":0,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"particles/cm³"},{"parameter":"um025","value":0.28,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"particles/cm³"},{"parameter":"um010","value":4.1,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"particles/cm³"},{"parameter":"pm25","value":41.1,"lastUpdated":"2021-08-09T20:49:38+00:00","unit":"µg/m³"}]}]}';
const json = JSON.parse(data);
let value = null;
const measurements = json?.results?.[0]?.measurements ?? null;
if(measurements)
for (const item of measurements)
if (item.parameter === 'pm25') {
value = item.value;
break;
}
if (value) {
// here you can use the value
console.log(value);
}
else {
// here you should handle the case where 'pm25' is not found
}

JSON.parse does not convert Stringified JSON Array

[
{ comicid: "5f55e91271b808206c132d7c", purchasetype: "pb_single" }
]
Above is my JSON Array that is stringified,I tried to JSON.parse and other functions like iterating it in a for loop but the key values also got scrambled.
Is there any way or an npm method that could instantly output the retrieved variable?
var cartItemFromLocalStorage = JSON.parse(localStorage.getItem("cartitem"));
if (cartItemFromLocalStorage != null) {
console.log("It came defined");
console.log("This is OG Array: " + cartItemFromLocalStorage);
let cartItemObject = {
//set object data
comicid: this.state.comicId,
purchasetype: this.state.purchaseType,
};
console.log(cartItemObject);
cartItemFromLocalStorage.push(cartItemObject);
localStorage.setItem("cartitem", result); //localstorage only supports strings
toast.success("Item Added to cart");
}
I checked the consoles and the states are putting up the data correctly.
I'm an extreme beginner in react js, help is much appreciated
The "JSON" you have written is actually JavaScript, not JSON. To convert it JSON use the JSON.stringify function, like so
> JSON.stringify([
{ comicid: "5f55e91271b808206c132d7c", purchasetype: "pb_single" }
]);
'[{"comicid":"5f55e91271b808206c132d7c","purchasetype":"pb_single"}]'
and then replace the value in localStorage with it.
Even easier would be to type into the developer console
localStorage.setItem("cartitem", JSON.stringify([
{ comicid: "5f55e91271b808206c132d7c", purchasetype: "pb_single" }
]));

Convert Unity3D json to Javascript Object json format

My whole workflow:
Unity3D(encoding class data in json format) -> WebGL Build -> Javascript html -> Socket.IO
Those data type(int, byte[], string) should be readable in socket.io.
This is the function I used in Unity3D, in order to convert a class to json string.
JsonUtility.ToJson();
When I print in node.js, I got this and it couldn't understand the data type.
{"Type":0,"Str":"AAA","Byte":[0]}
If it's correct, I will get below result when I print in node.js.
{ Type: 0, Str: 'AAA', Byte: [ 0 ] }
Thus, I need a solution to convert them.
Could someone please tell me the easiest way to convert them in C#?
UPDATE: more info
Below C# script is working in Unity3D, and I want to convert this:
Application.ExternalEval(#"
if(typeof window.socketIO !== 'undefined')
{
window.socketIO.emit('" + e + #"', " + data + #");
}
");
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html
Because "Application.ExternalEval" is depreciated in latest Unity, I need to convert them into something like this:
mergeInto(LibraryManager.library, {
WebSocketEmitData: function (_e, _data) {
var e = Pointer_stringify(_e);
var data = Pointer_stringify(_data);
if(typeof window.socketIO !== 'undefined')
{
window.socketIO.emit(e, data);
}
}
});
Thanks!
I use Javascript/Unity/C# heavily on my current project, I strongly advice you to use JSON.NET For Unity it will emit a universal json format, that is similar to the one on the javascript JSON class.
Usage pretty similar to unity's primitive json utility.
JsonUtility.ToJson => JsonConvert.SerializeObject
JsonUtility.FromJson => JsonConvert.DeserializeObject<T>
That being said, let's convert a json string from the C# object to a javascript object.
// Convert your json string to a native javascript object.
var jsObject = JSON.parse(str);
console.log(jsObject.Type); // outputs 0
console.log(jsObject.Byte.length); // outputs 1
console.log(jsObject.Str); // outputs AAA
// Convert your native javascript object to another of certain type,
// will assume the desired javascript type is Player in a namespace Database
var player = Object.assign(new Database.Player(), jsObject);
Also instead of if(typeof window.socketIO !== 'undefined') use if(typeof window.socketIO) it is cleaner, checks for both null and undefined.
Finally I found the answers myself. I didn't notice that I can emit object instead of string message. and now it works!
WebSocketEmitData: function (_e, _data) {
var e = Pointer_stringify(_e);
var data = Pointer_stringify(_data);
var obj = JSON.parse(data);
if(typeof window.socketIO !== 'undefined')
{
window.socketIO.emit(e, obj);
}
}

Renaming JSON properties if they contain a certain character without JSON.stringify

I have a bit of a unique problem. I'm currently trying to hook up a JSON dataSource to a kendo grid. Because of this, there can be no # anywhere in the JSON because it messes with kendo. So I have to take data like this:
[
{"ID#": "1", "Prop1": "Val1#"},
{"ID#": "2", "Prop2": "Val2"},
]
and escape the # so that Kendo can understand it:
[
{"ID\#": "1", "Prop1": "Val1\#"},
{"ID\#": "2", "Prop2": "Val2"},
]
The biggest problem with this is that the JSON could resemble just about anything: there could be any number/name of keys/values.
My Attempts:
I tried to escape the # like so: var dataSource = JSON.parse(result.replace("#", "\\#")); However, JSON.parse throws an error when I try this:
SyntaxError: JSON.parse: bad escaped character at line 1 column 7 of the JSON data
Then I tried to replace the # with &num;. It turns out Kendo can only support HTML entities in rows, not in column headers, without getting a template error. So I'm able to replace property values like this:
var dataSource = JSON.parse(result, function(key, value) {
if(typeof value === "string") {
return value.replace("#", "&num;");
}
else {
return value;
}
});
This works for values! However, the keys could still contain # which will mess up my Kendo Grid. I tried to loop through each object and key/pair and replacing the key if it has a #, but for some reason when I call Object.keys the array that is returned is just 0s and 1s even though that's not what my data is named.
for (var object in dataSource) {
for (var property in object) {
if (object.hasOwnProperty(property)) {
var keys = Object.keys(object);
for(var key in keys) {
var oldName = key;
var newName = key.replace("#", "\#");
object[newName] = object[oldName];
delete object[oldName];
}
}
}
}
This portion above appears to have no effect. It doesn't even throw an error.
I also tried replacing the # with a string: hashliteral. Then, after the kendo grid was created, I tried using jQuery to replace all of the hashliteral with #.
var fixed = $("#grid").html().replace(/hashliteral/g, "#");
$("#grid").html(fixed);
This does work, but it breaks the kendo grid and all of the bindings. The grid functionality is a must, so I can't use this solution.
Just to Recap
I'm trying to remove/replace or escape all # in JSON data so that it functions correctly with my Kendo Grid.
I can't use JSON.stringify and replace the # with \\# because then JSON.parse fails.
I can't use &num; because Kendo headers cannot have special characters.
I can't use jQuery to modify the $("#grid").html() because it breaks the grid bindings.
The key can be anything. The value can also be anything.
The JSON is NOT nested or complex.
I cannot define the field/title on the KendoGrid columns because I have no idea what the field/title needs to be, the data is very dynamic.
I'm about ready to give up on this and just remove all # from the data. If anyone can think of some way to accomplish this: renaming the properties of an object so that all # are preceded by a \, it would be much appreciated. For the life of me I can't find a solution to this problem.
I think you were already on the right track, but it's easier just to create a new list of objects:
var newObjects = [];
for (var i = 0; i < dataSource.length; i++ ) {
var currentObject = dataSource[i];
var newObject = {};
for (var key in currentObject) {
if (currentObject.hasOwnProperty(key)) {
var newKeyName = key.replace("#", "__HASHLITERAL__");
var newValue = currentObject[key];
if(typeof newValue === "string") {
newValue = newValue.replace("#", "__HASHLITERAL__");
}
newObject[newKeyName] = newValue;
}
}
newObjects.push(newObject);
}
console.log(newObjects);
Hope it helps and i understood your problem correctly.
Edit: You can't have special chars like \ as a key, so you have to actually use something unique like ___something___ which you could replace then with whatever later.

Parse JSON string to JavaScript object with function name

I have a JSON string stored in a data attribute.
{
"active": true,
"icons": {
"activeHeader": "ui-icon-alert"
},
"animate": {
"duration": 1000,
"always": dMethod
}
}
And I have a function which named dMethod:
function dMethod() {
alert("DONE");
}
When I try to parse the string via JSON.parse I get an error said invalid character. I check and the dMethod is defined when the parse method was running and if I removed the ,"always":dMethod part then the parser worked correctly.
I can't use quotation marks around the dMethod because then the type will be string type instead of object function.
Any help would be appreciated.
Thanks,
Péter
EDIT:
Thanks you for all the answers. I make some clarification so maybe better you understand the problem. I make a really simple js library to make jqueryui unobstructive:
var juiObjects = ["accordion", "autocomplete", "button", "datepicker", "dialog", "menu", "progressbar", "slider", "spinner", "tabs", "tooltip"];
$(document).ready(function() {
for (var i = 0; i < juiObjects.length; i++) {
var attributeName = "data-" + juiObjects[i];
$("["+ attributeName + "]").each(function () {
var optionsValue = $(this).attr(attributeName);
var options = JSON.parse(optionsValue);
$(this)[juiObjects[i]](options);
});
}
});
I had to choice between JSON.parse and eval. But I think eval wouldn't be so good choice. And try to keep the "library" as simple as possible. But it looks like I have sparete the code along the widgets.
Functions are not valid data types in JSON (see http://en.wikipedia.org/wiki/JSON#Data_types.2C_syntax_and_example).
I think you have to deserialize it as a string, then post-process your object and set "always" to your method.
It can be done by quoting the dMethod, by executing the function on the window object using the [] syntax:
function dMethod() {
alert("DONE");
}
var json = '{"active":true,"icons":{"activeHeader":"ui-icon-alert"},"animate":{"duration":1000,"always":"dMethod"}}'; // quoted
var obj = JSON.parse(json);
window[obj.animate.always]();
JSON.parse expects a valid JSON string. So, if you want to use it you should quote the dMethod function. Isn't it possible to replace the string "dMethod" with the real function after the parsing.
You can't parse that string as JSON, because it's not valid JSON.
You can turn the string into an object by executing it using the eval function, but of course the usual warnings about executing anything dynamically applies. If you don't have full control over what's in the string, it might be possible to use for cross site scripting.
var obj = eval(json);
obj.always();
This is how to serialize object with its functions:
JSON.stringify(YOUR_OBJECT, function (key, value) {
if (typeof value === 'function') {
return value.toString();
}
return value;
});
and this is how to deserialize it back:
JSON.parse(YOUR_JSON_STRING, function (key, value) {
if (value
&& typeof value === "string"
&& value.substr(0,8) == "function") {
var startBody = value.indexOf('{') + 1;
var endBody = value.lastIndexOf('}');
var startArgs = value.indexOf('(') + 1;
var endArgs = value.indexOf(')');
return new Function(value.substring(startArgs, endArgs)
, value.substring(startBody, endBody));
}
return value;
});

Categories