Strange JSONP syntax error - javascript

I'm stuck on this odd syntax error pointing to the colon in the first key:value pair of the json return. JSONLint.com says the json is valid. Can anyone help? JSFiddle linked below. Thanks
http://jsfiddle.net/gbkester/hgt8bvb8/
$(document).ready(function() {
$.ajax({
type: "GET",
url: "http://forecast.weather.gov/MapClick.php?lat=38.14000&lon=-78.45000&FcstType=digitalJSON",
dataType: 'jsonp',
success: function (json) {
console.log(json)
}
})
})

Doesn't seem to me that this response is actually JSONP. It looks like straight JSON.
Typically JSONP endpoints accept a callback= URL parameter. The value of this parameter is used to name a function that wraps the actual object. So, for example:
http://example.com/api/endpoint?callback=foobar
would return something like:
foobar({"key":"value"});
You can see jQuery trying this in the Fiddle:
http://forecast.weather.gov/MapClick.php?...&callback=jQuery11100967190676368773_1409103826888&_=1409103826889
The callback= is naming the function that it would like to see returned, and the _= is an attempt at cache busting. It wants to see a response that looks like:
jQuery11100967190676368773_1409103826888({ ... });
Adding or removing this parameter doesn't seem to change the response content. Not having the API docs handy, it's possible that they use a different parameter for this. If, for example, they used bazquux as the parameter, you could change your request to:
$.ajax({
...
url: "http://forecast.weather.gov/MapClick.php?lat=38.14000&lon=-78.45000&FcstType=digitalJSON&bazquux=?",
...
})
Note the literal &bazquux=?.

You're missing semicolons:
After console.log(json)
After the closing round bracket of the ajax block
After the closing round bracket of 'ready' function

Related

Why can't I pass a json array as data when doing GET request with jquery ajax?

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/

JQuery ajaxSubmit response always in lowercase

I am making an ajaxSubmit call to a web service, that will return XML.
When I make a call to the same service using XMLHttpRequest.send, the response is correct.
However if I use:
$(form).ajaxSubmit({
error: function _(response) {
$(iframeEl).remove();
config.error.call(scope, Thunderhead.util.JSON.decode(response));
},
success: function _(response) {
console.log(response);
$(iframeEl).remove();
var result = response;
config.success.call(scope, result);
},
iframe: true
});
This returns the correct XML response, but all tags have been transformed to lowercase.
I've checked the call in the Network tab in the developer console, and the case is correct in there, but when it is returned by the ajaxSubmit, it is lowercase.
Does anyone know what is causing this or how to rectify it?
Are you using Malsups jQuery form plugin
This plugin does a lot of toLowerCase transforms, I've not looked too closely but it does seem to lowercase the tag names of something, so this is probably your culprit.
I'd recommend refactoring to using a simple jQuery.ajax() call instead
$(form).on('submit', function(e) {
var url = $(form).attr('action');
e.preventDefault();
$.ajax( url, {
error: function _(jqXHResponse) {
// your code
},
success: function _(response) {
console.log(response);
// your code
}
});
This might be happening, because js is assuming xml as an answer. There is no difference for most xml-parsers which case is used in xml tag names.
I suggest trying to change response data type.
For example there is such option in jQuery.ajax method: http://api.jquery.com/jquery.ajax/ (named dataType). I would try using "text" dataType if case is really important.
Some further issues arose from this in the end, so just posting my eventual solution in case anyone else has this problem. I'm fairly new to javascript, so this might have been obvious to most, but it might help someone else out.
The success callback can actually take in 3 parameters, the third of which (arg2) is the actual response from the request, without any changes from the Malsups form plugin.
So in the end, the solution was simply to use this third parameter instead of the response parameter.
$(form).ajaxSubmit({
error: function _(response) {
$(iframeEl).remove();
config.error.call(scope, Thunderhead.util.JSON.decode(response));
},
success: function _(response, arg1, arg2) {
console.log(response);
$(iframeEl).remove();
var result = response;
config.success.call(scope, arg2.responseXML);
},
iframe: true
});

JQuery parse JSON

I'm fairly new to JQuery. The code below works and I can see the correct JSON response in Firebug. But I couldn't find a way how to get and parse it in the code. Alert window only shows
"[object Object]" but not any json text.
<script>
$.ajaxSetup({ cache: false });
var _token;
function make_token_auth(user, token) {
var tok = user + ':' + token;
return "Token " + tok;
}
$.ajax
({
type: "GET",
url: "url",
dataType: 'json',
beforeSend: function (xhr){
xhr.setRequestHeader('Auth', make_token_auth('userid', 'token'));
},
success: function (data){
alert(data);
}
});
</script>
The fact you precised
dataType: 'json',
tells jQuery to parse the received answer and give it as a javascript object to your success callback.
So what you have here is fine and what is alerted is correct (this is an object, so
alert simply prints the result of data.toString()).
Use console.log to see what it is exactly :
success: function (data){
console.log(data);
}
and open the developer tools in Chrome or the console in Firebug to browse the properties of the object.
don't use alert() for debugging -- it's often unhelpful (as in this case), and also has serious issues when used with asyncronous code (ie anything Ajax) because it interrupts the program flow.
You would be much better off using the browser's console.log() or console.dir() functions, and seeing the object displayed in the console. It is much more functional, and doesn't interrupt the flow of the program.
So instead of alert(myjsonvar) use console.log(myjsonvar).
You can get the json string by using JSON.stringify
var jsonstr = JSON.stringify(data);
alert(jsonstr);
The alert function expects you to pass in a string or number.
Try doing something like this:
for(x in data) {
alert(x + ': ' + data[x]);
}
Update in response to comments: You can use alert in development or production to see string and number values in the object returned by the server-side code.
However, carefully rereading your question, it looks like what you really want to see is the actual JSON text. Looking at #dystroy's answer above, I think that if you remove the dataType: 'json' from your $.ajax invokation, jQuery will treat the response as plain text instead of automatically converting it to an Object. In this case, you can see the text by passing it to the alert function.
Try using
data = JSON.parse(data)
Then do whatever you want with the data.
Source: JSON.parse() (MDN)

How do I prevent jQuery $.ajax from adding a leading ampersand to the query string in the request?

I'm trying to avoid handling this improperly encoded request on the server. I have a request with a single parameter like this:
$.ajax({
url: "http://someplace.ontheinternets/count?",
data: {
days_since_epoch: 15460
},
dataType: "json",
success: function(data) {
// Do something with data
}
});
This is giving me: http://someplace.ontheinternets/count?&days_since_epoch=15460
The leading ampersand is giving me problems on the other end (interpreted as two parameters with the first one being empty). Seems like an easy fix, but I did not see this specific issue in the related questions. Any suggestions would be helpful.
Don't put the ? on it in your url parameter. Since you have it there, jQuery thinks the URL already has other parameters, and so adds the ones you asked it to add using an &. If you remove the ? from the end of your url parameter, jQuery won't be fooled and will (for a single parameter) just use ?.

Should be really simple Jquery jsonp

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.

Categories

Resources