Parsing JSON in javascript for multiple browsers - javascript

I'm trying two different approaches. One works in only Firefox, the other works in Safari, but neither work in both. The one that works in Firefox is:
var json = JSON.parse(data);
var results = json.query.results.quote;
The one that works in Safari
var results = data.query.results.quote;
Where data is the JSON that is being returned from a server. Is one of these the proper ways to parse JSON, and what's the best way for browser compatibility
EDIT:
When I debug in Safari using JSON.parse I get the error: Unexpected identifier "object"

If you are using jQuery to get this JSON data, you don't need to worry about parsing it. jQuery can (and sometimes will) do it for you.
Your problem is (probably) that it is already being parsed for you. If you server returns the Content-type: application/json header, jQuery will parse it for you. If it returns a different header, like text/html, then it won't be parsed as JSON. It's never good to be unsure of what a variable contains.
To tell jQuery to always parse it as JSON, use dataType: 'json'. This makes sure that the data in your callback is always an object.
$.ajax({
url: 'file.php',
dataType: 'json',
success: function(data){
var results = data.query.results.quote;
}
});

You can use the official implementation of JSON by Douglas Crockford. It's available here. Major libraries make sure to add JSON functionality. It is also very easy to check if a native implementation of JSON is available within the existing browser.
The JSON library already does that. It checks to see if the browser already has JSON.parse and JSON.stringify implemented. If it does, it won't override anything. If it doesn't it will give you the functionality you need.

Related

Why declare variable with json in js file instead of reading json?

Recently I've been working with leaflets, and I'm currently looking at several plugins.
Several of the plugins I've seen (including Leaflet.markercluster) use json to plot points, but instead of using the actual stream, or a json file, the programmer includes a javascript .js file where a variable is set with the json stream. So the js file with the json data looks like this:
var data = [
{"loc":[41.575330,13.102411], "title":"aquamarine"},
{"loc":[41.575730,13.002411], "title":"black"},
{"loc":[41.807149,13.162994], "title":"blue"},
{"loc":[41.507149,13.172994], "title":"chocolate"}
]
I've been working with other type of javascript charts, and most of them read and process a json stream.
It seems these plugins will not work if I create a service that returns json.
Why not use json instead of including a js file that sets a variable with a json stream?
I'm not a javascript expert, but I find it easier to generate json than a javascript file with json in it.
You are wrong about concepts.
1st. JavaScript as a language has its own syntax, so, if you have a function that receive a JSON object as a parameter and you pass it a Number or a String, it'll will throw an Error when you try to access some property. For Ex.
function myjson (obj) {
console.log(obj.prop)
}
myjson(34); //wrong
myjson("{prop: 123}") //wrong
myjson({prop: 123}) //Good, will print 123
Now, imagine that you have some scripts, many .js files that you have indexed in your HTML file, like
<script src="/mycode.js"> </script>
<script src="/myapp.js"> </script>
And you want to add some data, like the one you show for the plot points; then you have to include it in two ways, putting that in a .js file or getting it from a service with an AJAX call.
If you add that in a .js file, you'll have access to them directly from your code, like this
var data = [
{"loc":[41.575330,13.102411], "title":"aquamarine"},
{"loc":[41.575730,13.002411], "title":"black"},
{"loc":[41.807149,13.162994], "title":"blue"},
{"loc":[41.507149,13.172994], "title":"chocolate"}
]
console.log(data)
and if you put that in a .json file file this
/mydata.json
[
{"loc":[41.575330,13.102411], "title":"aquamarine"},
{"loc":[41.575730,13.002411], "title":"black"},
{"loc":[41.807149,13.162994], "title":"blue"},
{"loc":[41.507149,13.172994], "title":"chocolate"}
]
you'll have to fetch and parse the data yourself
fetch("/mydata.json").then(async data => {
var myjson = await data.text();
myjson = JSON.parse(myjson);
console.log(myjson) //A Javascript object
console.log(myjson[1]) //The first element
})
I like #FernandoCarvajal's answer, but I would add more context to it:
JSON is more recent than JS (you could see JSON as a "spin-off" of JS, even though it is now used in combination with much more languages than just JS).
Before JSON was widespread, the main and easiest way to load external data in Browsers was the technique you saw in the plugins demo: assign data into a global variable, which you can use in the next script. Browsers happily execute JS even from cross domain (unless you explicitly specify a Content Security Policy). The only drawback is that you have to agree on a global variable name beforehand. But for static sites (like GitHub pages in the case of the plugins demo you mention), it is easy for the developer(s) to agree on such a convention.
At this stage, you should understand that using this simple technique already fits the job for the sake of the plugins static demo. It also avoids browsers compatibility issues, aligning with Leaflet wide browsers compatibility.
With the advent of richer clients / Front-End, typically with AJAX, we can get rid of the global variable name agreement issue, but now we may face cross domain difficulty, as pointed out by #Barmar's comment. We also start hitting browsers compatibility hell.
Now that we can load arbitrary data without having to agree on a static name beforehand, we can leverage Back-End served dynamic content to a bigger scale.
To workaround the cross domain issue, and before CORS was widespread, we started using JSONP: the Front-End specifies the agreed (callback) name in its request. But in fact we just fallback to a similar technique as in point 2, mainly adding asynchronicity.
Now that we have CORS, we can more simply use AJAX / fetch techniques, and avoid security issues inherent to JSONP. We also replace the old school XML by the more JS-like JSON.
There is nothing preventing you from replacing the old school technique in point 2 by a more modern JSON consumption. If you want to ensure wide browsers compatibility, make sure to use libraries that take care of it (like jQuery, etc.). And if you need cross domain, make sure to enable CORS.

Working around recent $.parseJSON change

With jQuery 1.9, they changed $.parseJSON to behave in the same way as JSON.parse. The most notable change that has caused me headaches is that now empty strings are considered invalid JSON, and cause jQuery to throw an error.
In the codebase who's version of jQuery I am upgrading, there are many places where we are making ajax requests with dataType: 'json', and in some of those instances there are situations where the server may respond with an empty string. This wasn't an issue in our current version of jQuery, but I'm trying to upgrade, and its causing problems.
It would be a daunting task to change all of the instances of $.ajax with dataType: 'json', in the codebase just to work around the error that $.parseJSON throws, so I am looking for an alternative way of working around this issue. Would something like $.ajaxPrefilter work?
The best solution I could think of is to intercept data that comes in via all ajax calls with dataType: 'json' and pre-process it it using something similar to jQuery's own suggested workaround, to make it work without having to change each ajax call individually.
You can use ajaxSettings() to override the default converters:
$.ajaxSettings({converters: { "text json": yourSafeParseJSON } })

Set content type based on browser

I am using asp.net mvc 3 and returning json to the user. I'm doing that with:
return Json(results, JsonRequestBehavior.AllowGet)
results is just a simple viewmodel c# class I created. That works fine in FF and chrome, but then IE 9 asks to open or save the results. Everywhere I look, people say the "fix" is to do something like:
return Json(results, "text/html", JsonRequestBehavior.AllowGet)
This does work for me in IE, but it doesn't work in chrome and/or firefox. It does for some versions, but not all. I was wondering if it's possible to return text/html if the browser is IE, otherwise return the normal JSON. Or is there a better solution? Thanks in advance!
I am assuming that you are doing an AJAX call, if so the solution you have is the correct way to make ALL browsers treat the returned values as HTML, which is a much better solution than dealing with each browser in a different way.
However, in order to be able to work with the returned values, you will need to parse the returned html into JSON.
In the success callback of the AJAX call, simply add the following:
var jsonResponse = $.parseJSON(response);

How to access JSON from an iframe originating from same domain?

In my webpage a hidden iframe is loaded with some JSON in it. This JSON is refreshed by some actions on the page. How do I access this JSON in iframe from my web page? for some unknown arcane unexplainable reason I am forced to use jQuery 1.3.2. so no $.parseJSON()
I think you can use:
var json = $.parseJSON($("#hiddeniframe").contents().text());
Something along those lines will work at least.
All modern browsers include a JSON parsing library:
var data = JSON.parse($("#hiddeniframe").contents().text());
If you need to support older browsers there are several libraries to choose from that will provide the same interface. The better ones will check to see if the browser is providing a native implementation and not override it, since it's bound to be faster.
See also JSON.stringify()
The code #Paulpro posted:
var json = $.parseJSON($("#hiddeniframe").contents().text());
doesn't work for me.
I changed the code to:
var json = $.parseJSON($("#hiddeniframe").contents().find("*").first().text());
And now it works.

Using JSON in XUL <template>s

As far as I can tell, the template feature in XUL doesn't allow you to load JSON data into your listbox/tree/etc. element. -- it only supports XML and RDF. The closest thing I found to an indication that it might someday support JSON, is the comments on this blog post from 2007, saying that there was a bug filed. But the bug in question is marked RESOLVED FIXED and JSON is still not supported. So I guess my options are:
Get the data I need in XML, and display it using templates.
Get the data in JSON, and display it by direct DOM manipulation.
Use one of these third-party templating solutions.
So my question is, am I correct that templates don't support JSON? If not, where is that feature documented? If I am correct, what should I consider when choosing among the above three options?
It turns out that writing your own custom object that implements nsITreeView is a lot simpler than I expected, and makes everything seem nice and fast.
I'm not sure about JSON in XUL templates, however I'd suggest option 2, given the ease with which JSON is used within the browser.
From Firefox 3.5, you can just do
var obj = JSON.parse(xhr.responseText);

Categories

Resources