i'm doing an ajax request with query and wondering why my response is already a JS object.
If i do a
var obj = jQuery.parseJSON(response);
'obj' is null, but i can use 'response' as an array of js objects.
This is not really a problem, but i would like to understand this behavior.
Thanks
This happens when you make an AJAX call and specify the dataType JSON jQuery calls jQuery.parseJSON on the response for you. In fact you can specify what function to call depending on the dataType as you can se from the documentation
converters(added 1.5)
Map Default: {"* text": window.String, "text
html": true, "text json": jQuery.parseJSON, "text xml":
jQuery.parseXML} A map of dataType-to-dataType converters. Each
converter's value is a function that returns the transformed value of
the response
So if you make a call like this
$.ajax({
url: yoururl,
dataType: "json",
success: function(data){
//data is already a json
}
If you don't specify a dataType jQuery tries to guess it
dataTypeString Default: Intelligent Guess (xml, json, script, or
html)
The type of data that you're expecting back from the server. If none
is specified, jQuery will try to infer it based on the MIME type of
the response (an XML MIME type will yield XML, in 1.4 JSON will yield
a JavaScript object, in 1.4 script will execute the script, and
anything else will be returned as a string). The available types (and
the result passed as the first argument to your success callback) are:
"xml": Returns a XML document that can be processed via jQuery.
"html": Returns HTML as plain text; included script tags are evaluated
when inserted in the DOM. "script": Evaluates the response as
JavaScript and returns it as plain text. Disables caching by appending
a query string parameter, "=[TIMESTAMP]", to the URL unless the cache
option is set to true. Note: This will turn POSTs into GETs for
remote-domain requests. "json": Evaluates the response as JSON and
returns a JavaScript object. In jQuery 1.4 the JSON data is parsed in
a strict manner; any malformed JSON is rejected and a parse error is
thrown. (See json.org for more information on proper JSON formatting.)
"jsonp": Loads in a JSON block using JSONP. Adds an extra
"?callback=?" to the end of your URL to specify the callback. Disables
caching by appending a query string parameter, "=[TIMESTAMP]", to the
URL unless the cache option is set to true.
"text": A plain text
string. multiple, space-separated values:
As of jQuery 1.5, jQuery can
convert a dataType from what it received in the Content-Type header to
what you require. For example, if you want a text response to be
treated as XML, use "text xml" for the dataType. You can also make a
JSONP request, have it received as text, and interpreted by jQuery as
XML: "jsonp text xml." Similarly, a shorthand string such as "jsonp
xml" will first attempt to convert from jsonp to xml, and, failing
that, convert from jsonp to text, and then from text to xml.
It pretty much depends which dataType you pass into your jQuery ajax request. This might happen implict by calling .getJSON() or directly using $.ajax().
However, if you omit the dataType, jQuery trys to do some magic and guesses which data was received. As for JSON data, it uses a simple regular expression to check if a response looks like a JSON-string and if so, it automatically parses it for you.
jQuery will try to infer it based on the MIME type of the response.
So always be precise and tell jQuery which type of data you expect.
The default behaviour of jQuery's ajax method is to analyse the response and return it as the most appropriate data type. If your response looks like JSON, therefore, it will be converted to a JavaScript object/array.
You can override this behaviour by setting the dataType attribute in the ajax settings.
if you specify the dataType as json the jquery parses the response for you like
$.ajax({
...
dataType:'json',
...
});
same is the case with jQuery.getJSON()
this is how the source code for getJSON looks like
getJSON: function( url, data, callback ) {
return jQuery.get( url, data, callback, "json" );
},
https://github.com/jquery/jquery/blob/master/src/ajax.js#L283
Because
jQuery.ajaxSettings.converters["text json"] === jQuery.parseJSON
I.E it will run the function everytime json response is detected automatically or explicitly set by yourself
Related
Just getting a simple .json file and parsing it, or not. Both fail anyway. I tried the solutions from other threads and none worked. console.log() shows an object, but I cant use it. I tried changing the json a few different ways but that didnt work. This is the .json file:
[ {
"name": "Alabama",
"abbreviation": "AL"
},
{
"name": "Alaska",
"abbreviation": "AK"
},
{
"name": "American Samoa",
"abbreviation": "AS"
},
{
"name": "Arizona",
"abbreviation": "AZ"
}]
It looks ok to me. So I added this function to use it:
function fillStates(){
var obj = $.get('states.json');
console.log(obj);
var states = JSON.parse(obj);
//console.log(states);
}
I guess you are misunderstanding jQuery $.get() method. It will return a Promise object and not the data you want:
As of jQuery 1.5, all of jQuery's Ajax methods return a superset of the XMLHTTPRequest object. This jQuery XHR object, or "jqXHR," returned by $.get() implements the Promise interface, giving it all the properties, methods, and behavior of a Promise (see Deferred object for more information). The jqXHR.done() (for success), jqXHR.fail() (for error), and jqXHR.always() (for completion, whether success or error) methods take a function argument that is called when the request terminates. For information about the arguments this function receives, see the jqXHR Object section of the $.ajax() documentation.
That's why you are giving a [object Object] to JSON.parse() function.
You must use a success callback:
function fillStates(){
var obj = $.get('states.json', function(data) {
// It will be executed in case of sucess
console.log(data);
});
}
Usage of $.get is not correct since it is an async execution. This should work:
$.get( "states.json", function( obj ) {
var states = JSON.parse(obj);
});
Let's backup and examine what $.get() is. This method is simply a shorthand method for:
$.ajax({
url: url,
data: data,
success: success,
dataType: dataType
});
See the reference documentation. Now let's jump over to the $.ajax documentation to understand how jQuery parses the return value:
Per the documentation:
dataType (default: Intelligent Guess (xml, json, script, or html))
Type: String
The type of data that you're expecting back from the server. If none is specified, jQuery will try to infer it based on the MIME type of the response (an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string). The available types (and the result passed as the first argument to your success callback) are:
"xml": Returns a XML document that can be processed via jQuery.
"html": Returns HTML as plain text; included script tags are evaluated when inserted in the DOM.
"script": Evaluates the response as JavaScript and returns it as plain text. Disables caching by appending a query string parameter, =[TIMESTAMP], to the URL unless the cache option is set to true. Note: This will turn POSTs into GETs for remote-domain requests.
"json": Evaluates the response as JSON and returns a JavaScript object. Cross-domain "json" requests are converted to "jsonp" unless the request includes jsonp: false in its request options. The JSON data is parsed in a strict manner; any malformed JSON is rejected and a parse error is thrown. As of jQuery 1.9, an empty response is also rejected; the server should return a response of null or {} instead. (See json.org for more information on proper JSON formatting.)
"jsonp": Loads in a JSON block using JSONP. Adds an extra "?callback=?" to the end of your URL to specify the callback. Disables caching by appending a query string parameter, "=[TIMESTAMP]", to the URL unless the cache option is set to true.
"text": A plain text string.
multiple, space-separated values: As of jQuery 1.5, jQuery can convert a dataType from what it received in the Content-Type header to what you require. For example, if you want a text response to be treated as XML, use "text xml" for the dataType. You can also make a JSONP request, have it received as text, and interpreted by jQuery as XML: "jsonp text xml". Similarly, a shorthand string such as "jsonp xml" will first attempt to convert from jsonp to xml, and, failing that, convert from jsonp to text, and then from text to xml.
So to sum things up, jQuery will interpret the response using it's intelligent guess method since you didn't specify a return data type. The data type will be inferred as JSON and will be parsed to a JavaScript object. For this reason, you shouldn't ever need to do JSON.parse(...) on the returned data when using a jQuery based ajax method such as $.get, $.post, $.ajax, $.load (the data method, not the event handling suite method) or $.getJSON.
Continuing on, AJAX stands for asynchronous JavaScript and XML. The asynchronous part is key here. The request is operated out of band while JavaScript execution continues on the page starting at the next line. In your case obj will be a $.promise, not the result. Parsing this using JSON.parse will result in an error.
You have two options from here:
Wait for the promise to resolve and execute on it using .done().
Pass a success callback function to execute upon successful completion of the ajax request.
Both examples are outliend below:
Using .done():
var obj;
function fillStates() {
$.get('states.json').done(function (data) {
obj = data;
console.log(obj);
});
}
Using a success callback:
var obj;
function fillStates() {
$.get('states.json', function (data) {
obj = data;
console.log(obj);
});
}
Before JSON.parse(), just check typeOf obj==='object'. If true then there is no need to parse as variable is already an object.
If I run a get request like this:
$.ajax({
url: 'http://localhost:8000/api/points/',
contentType:"application/json",
dataType: "json",
data: JSON.stringify({"content_type":content_type,"object_id":object_id}),
type: 'GET',
}).error(function(r){ $(output).text('error') })
.success(function(r){
$(output).text(r.count);
})
Its request goes to:
http://localhost:8000/api/points/?{%22content_type%22:8,%22object_id%22:40}
Obviously that's bad. It works okay if I don't do JSON.stringify(), but why is that?
Curiously if I do a POST request it's the opposite! I have to stringify the data or it won't work. So why the difference?
First of all let's fix your request:
var req = $.ajax({
method: "GET",
url: "http://localhost:8000/api/points/",
dataType: "json", // is you telling jQuery what kind of response to expect.
data : {id : '12345'}
});
req.done(function(data){
// do something with the data
});
req.fail(function(jqXHR, status, err){
// do something in case of failure
throw err;
});
Next get to know what you are dealing with :
data : PlainObject or String or Array
Data to be sent to the server. It is converted to a query string, if not already a string. It's appended to the url for GET-requests. By default, data passed in to the data option as an object (technically, anything other than a string) will be processed and transformed into a query string, fitting to the default content-type "application/x-www-form-urlencoded".
Note: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks will be deprecated in jQuery 1.8. To prepare your code for their eventual removal, use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.
At last:
No need for : JSON.stringify({"content_type":content_type,"object_id":object_id}) as it is a wrong way to do it with JSON.stringify just :
{ 'content_type' : 'type', 'object_id' : 'id' }
Urahara's answer contains some useful suggestions, but does not seem to address your question.
Well, it seems that your server side code is expecting to find a json object in the body of the POST request. Why would that be? Because you specify that the content type be "application/json". So in the case of a PUT case, when you use JSON.stringify your data in the $.ajax call is a string that happens to represent a JSON object. This is passed as is and so this works. You end up sending something like
{"content_type":8, "object_id":40}
as the body of your POST request and your server side code is happy to process this. Not sure exactly what your server-side technology is, but presumably it also binds content_type to 8 and object_id to 40, which makes you happy :-)
But when you do not use JSON.stringify to turn the object into a JSON string, you end up passing the object itself to $.ajax having it turn it into a string in the way it knows how. Well, it only knows only one: the good old url-encoding way. So the server, would still be expecting a JSON object but would instead be getting
content_type=8&object_id=40
as the body of the PUT request. It will not be happy. This is not a JSON object like your content-type promised! :-)
Now, moving on to the case of a GET request. Here the content-type is pretty much irrelevant as the message body will be empty. If you use JSON.stringify what you pass as the request data is a weird JSON-object representing string and the monstrosity that you get as a URL
http://localhost:8000/api/points/?{%22content_type%22:8,%22object_id%22:40}
is as you 'd expect not very well received by the server. What the server is happy with is something like
http://localhost:8000/api/points/?content_type=8&object_id=40
Which is exactly what $.ajax produces when you do not use JSON.stringify but rather pass it a nice pair of attribute-value pairs. It just url-encodes them, exactly like it did in the PUT case, and the server is happy.
So $.ajax always url-encodes objects consisting of attribute-value pairs. This is fine in most cases. One way to fix your code to do a POST without using JSON.stringify would be to simply not put a content type parameter in the $.ajax call (in which case the default, 'application/x-www-form-urlencoded; charset=UTF-8' will be used).
But if you want to pass more complex, deeply hierarchical objects, using some object serialisation format you have to set the appropriate content type and pass the data as a string using the corresponding encoding (JSON, XML, etc.) like you did here.
Hope that answers your question :-)
Please also have a look at http://api.jquery.com/jquery.ajax/
in my code i have:
$.ajax({
url: 'http://chapters.zmgc.net',
dataType: 'jsonp',
success: function(d){ // "Type","Name","Link","Contact","Location","Icon"
Tabzilla.zgContacts = d;
var countries = [];
d.rows.forEach(function(row){
if (row[0] == 'Country') countries.push(
{link:row[2], contact:row[3], country: row[4]}
);
});
but i get an error, Uncaught SyntaxError: Unexpected token :
{
"kind": "fusiontables#sqlresponse",
....
if i replace the url with the actual file and remove the dataType, all works as expected!
i have validated the output of http://chapters.zmgc.net at http://jsonlint.com/ and it is ok.
looking at the response headers returned from http://chapters.zmgc.net, it is:
Connection:keep-alive
Content-Type:application/json
Date:Thu, 13 Dec 2012 17:02:27 GMT
Transfer-Encoding:chunked
here is the code https://github.com/tomarcafe/Z-Tabzilla/blob/gh-pages/z-tabzilla.js#L282 i would like to replace the local file with reading the remote data?
what am i missing?
You shouldn't set type to jsonp, That is JSON with padding, in that it is assumed that response is wrapped inside a function call.
callback({payload: values});
and will tried to be executed.
Instead use type: json, or simply $.getJSON which will correctly pass the JSON payload with $.parseJSON.
It's because you're asking for JSONP (JSON with padding) and getting JSON without padding. JSONP is JSON that is padded by a function call, and the only way to get it to work is by adding support for JSONP on the server.
If you don't have access to chapters.zmgc.net you'll have to contact them and ask them to add support for JSONP.
If you do have access you can add ?callback=parseThis to your url and then read that variable on server-side and pad your JSON accordingly:
parseThis(/* put your json in here */);
However, if you don't define your own callback, jQuery will add one automatically that you can use. They will look something like this: jQuery18200710562220774591_1355419375476
As Ajax uses jsonp (json with padding) but your url doesn't seem to be jsonp compatible, so you have to avoid using that.
from jQuery:
"jsonp": Loads in a JSON block using JSONP. Adds an extra
"?callback=?" to the end of your URL to specify the callback. Disables
caching by appending a query string parameter, "_=[TIMESTAMP]", to the
URL unless the cache option is set to true.
more here : http://bob.ippoli.to/archives/2005/12/05/remote-json-jsonp/
I am parsing generated json with jquery $.ajax but there is one option that I dont understand. I saw it in some examples and tried to look for at jquery.com but still not sure about it:
this option is:
data: { get_param: 'value' }
which is used like this:
$.ajax({
type: 'GET',
url: 'http://example/functions.php',
data: { get_param: 'value' }, //why we shell use that in that case?
success: function (data) {
var names = data
$('#cand').html(data);
}
});
I know that "data:" is what sent to the server but parsing JSON I thought i don't send but retrieve from server with GET type. And the next part "get_param: 'value'"
does not make sense to me in that case either, could anyone please explain when and what for and in what cases it shell be used?
thank you.
I know that "data" is what sent to the server
Yes. If data is an object, it gets serialized to an application/x-www-form-urlencoded string and then placed in the query string or request body as appropriate for the request type (GET/POST).
jQuery does all the escaping necessary for this.
(It also, by default, collapses nested data structures (you don't have any in your example) into PHP-style by adding [] to key names).
but parsing JSON
JSON is not involved (unless the server responds with some).
when and what for and in what cases it shell be used
Whenever you want to pass data to the server rather than requesting a static URI.
You don't send JSON (usually), you send simple GET or POST HTTP parameters. They are given to the ajax method in an object literal usually, but you could have used the string "getparam=value", too. If you provide an object, jQuery will do the parameter-serialisation and URL-encoding for you - they're sent as x-www-form-urlencoded.
To cite from the docs:
data (Object, String)
Data to be sent to the server. It is converted to a query string, if
not already a string. It's appended to the url for GET-requests. See
processData option to prevent this automatic processing. Object must
be Key/Value pairs. If value is an Array, jQuery serializes multiple
values with same key based on the value of the traditional setting.
Why does this not work? anybody:
In my code I have:
$.getJSON("http://isp123.co.uk/cw/NorthWales/Test.txt?jsoncallback=?",
function(data){
//This never gets executed
alert('here');
});
The text file can be viewed here:
http://isp123.co.uk/cw/NorthWales/Test.txt
This is not a JSONP response:
({"name" : "hello world"});
If you had a proper JSONP response, then your code should work.
The question mark in the "callback=?" part of the URL is changed by jQuery before making the request, your JSONP server needs to be able to dynamically create the JSONP "function" in response to the unique jQuery request. If you can't dynamically create your JSONP, perhaps you could use YQL/Yahoo pipes to turn it into JSONP?
This pipe should do the trick, to see if it works, use this URL instead in your getJSON function: http://pipes.yahoo.com/pipes/pipe.run?u=http%3A%2F%2Fisp123.co.uk%2Fcw%2FNorthWales%2FTest.txt&_id=332d9216d8910ba39e6c2577fd321a6a&_render=json&_callback=?
I just tried this and it worked:
$.getJSON("http://pipes.yahoo.com/pipes/pipe.run?u=http%3A%2F%2Fisp123.co.uk%2Fcw%2FNorthWales%2FTest.txt&_id=332d9216d8910ba39e6c2577fd321a6a&_render=json&_callback=?", function(data){
//This always gets executed!!!
alert('here');
});
I don't know if you know enough about JSONP but this is not JSONP
?({"name" : "hello world"});
It really should be something like this http://isp123.co.uk/cw/NorthWales/Test.txt?jsoncallback=foo
foo({"name" : "hello world"});
From the jQuery.getJson manual page:
Important: As of jQuery 1.4, if the JSON file contains a syntax error, the request will usually fail silently. Avoid frequent hand-editing of JSON data for this reason. JSON is a data-interchange format with syntax rules that are stricter than those of JavaScript's object literal notation. For example, all strings represented in JSON, whether they are properties or values, must be enclosed in double-quotes. For details on the JSON format, see http://json.org/.
Your JSON is invalid according to http://jsonlint.com/
Here Clearly mentioned
As of jQuery 1.5, setting the jsonp
option to false prevents jQuery from
adding the "?callback" string to the
URL or attempting to use "=?" for
transformation. In this case, you
should also explicitly set the
jsonpCallback setting
and read jsonpCallback section
jsonpCallback,
Specify the callback function name for
a JSONP request. This value will be
used instead of the random name
automatically generated by jQuery. It
is preferable to let jQuery generate a
unique name as it'll make it easier to
manage the requests and provide
callbacks and error handling. You may
want to specify the callback when you
want to enable better browser caching
of GET requests. As of jQuery 1.5, you
can also use a function for this
setting, in which case the value of
jsonpCallback is set to the return
value of that function
Probably worth using jQuery.ajax() - http://api.jquery.com/jQuery.ajax/
You can pass in the dataType as "jsonp" and then jQuery takes care of all the callback business, but more importantly you can specify a function to run when there's an error, which may help you:
$.ajax({
dataType: "jsonp",
success: function(d) {console.log(d);},
error: function() { console.log("error") } //do your debugging in here
//add other parameters such as URL, etc
});
The error function you define can be passed 3 variables, read up on it on the ajax() page on the jQuery docs (linked at the beginning of my post) to find out more about that and how to use them.
Your problem lies with how your server is outputting the information. In the link you've supplied, the assumption is that any name placed in the ?jsonpcallback should result in wrapping the JSONP code in a function with that same name. It, however, is not the case.
So the next option is this: use a static function name in your server file and wrap the code. (e.g. use foo(<jsonp>) and stick with it) Then, you have to explicitly tell jQuery that we are going to use a specific function name (leave jQuery with the assumption it's supplying (and thus receiving) that name back, when in-fact you're just supplying it server side and filling in the blanks).
Once you have your file setup, use something like the following:
$.ajax({
// setup the request
url: 'http://isp123.co.uk/cw/NorthWales/Test.txt',
crossDomain: true,
dataType: 'jsonp',
jsonp: false,
jsonpCallback: 'foo', // "supply" the jsonp function (pseudo-defined)
// function to call when completed
complete: function(data){
alert(data);
}
// just in case, catch the error
error: function(j,t,e){
alert('AJAX Error');
}
});
So now when jQuery makes the call and it thinks it's supplying the callback, it's really just getting the server-defined callback in return. So, for the above to work, your text file should look something like this:
foo({name:"Hello, World!"});
Also, if you can, change your header to application/javascript, though this is some-what optional.