Synchronous jQuery calls, without putting everything in the callback - javascript

Is it possible to get a JSON in jQuery synchronously without using the async: false option (which apparently has been deprecated)? I also would prefer not to put everything into the success function.

No, there is no other option than async: false. I wouldn't recommend it if there were.
For the success function, you can simply pass another function that will be executed.
For example:
$.ajax( {
url: myUrl,
type: 'POST',
success: myFunc
} );
function myFunc( datas ) {
// do what you should do in a success function
}

Since ajax methods on jQuery return a Deferred Object (jQuery 1.5+) you could also write
$.ajax({
url: myUrl,
type: 'POST'
}).done(function() {
// do what you should do in a success function
});

Not reasonably. Trying to force the request to be Synchronous without using asyc:false is possible, but a waste of effort in my opinion. In pretty much every scenario you want to use async:true, you will be able to accomplish all of the same things with async:true as you can with async:false. It's just a matter of how you structure your code.
If you look at the current version of the source file that executes the AJAX request:
https://github.com/jquery/jquery/blob/master/src/ajax/xhr.js
You will see it still uses the async field on the settings object, this field is passed directly into the Open method of the XMLHttpRequest object. So using the default implementation all you can do, is set "async: false".
if ( s.username ) {
xhr.open( s.type, s.url, s.async, s.username, s.password );
} else {
xhr.open( s.type, s.url, s.async );
}
Now assuming you are really stubborn and want to do this without setting "async:false", you could get really bold and write a custom ajaxTransport and register it with a custom data type.
Here is an example I wrote that creates a custom transport object with a send and abort method, and registers it with the dataType 'mine'. So when you specify dataType 'mine' in your ajaxSettings object it will use this custom transport instead of the one built into jQuery. http://jsfiddle.net/xrzc7/ Notice there are two ajax requests one with the 'mine' dataType that show the alert, and one without the data type that does not show the alert. My ajaxTransport in this example isn't fully functional, its just to illustrate that you can swap in your own send function.
I wouldn't advise writing your own ajaxTransport for jQuery because it really isn't neccessary in my opinion, but to answer your question I'm suggesting it as an option.
You should pay close attention to how the default ajaxTransport in jquery is written, and how it interacts with the settings object and callback methods when writing your custom ajaxTransport. Your send function would obviously force a "false" value as the async parameter of the XMLHttpRequest.open method.
https://github.com/jquery/jquery/blob/master/src/ajax/xhr.js - this is the current source code for the default ajaxTransport mechanism.
Hope this helps, or perhaps persuades you to always use async:true. :-D

Related

Execute unobtrusive Javascript after Ajax call

I want to use John Resig's pretty date for replacing my ugly time stamps with some nice-to-read time specification.
So I thought about using the following unobtrusive html markup:
<span data-type="prettyDate">25.04.2012 10:16:37</span>
Acording to that I use following Javascript/jQuery to prettify the date:
$(function() {
$('[data-type="prettyDate"]').prettyDate();
}
My problem is that I don't know how to deal with markup that is loaded using ajax because that would not be caught since it does not yet exist when the DOM ready event fires. Reacting to events on "ajaxed" elements is pretty easy using the on handler. But this is not an event.
You have to call .prettyDate() after each Ajax response is added to the DOM. A simple way to do that is to set a global complete handler with ajaxComplete.
You can use jQuery to target dynamic content before it's actually been inserted into the document, something like:
success: function(html) {
var $html = $(html);
$html.find('[data-type="prettyDate"]').prettyDate();
$(somewhere in document).append($html);
}
What you want to do to get the best performance out of this is have a function which get called on the data as it gets returned from the ajax callback. That way you can prettify your date before adding them to the DOM.
You don't want to call pretty date on element in the DOM every time as you will process date already done too.
So, something like this.
$.ajax({
url:'someurl',
success: function(data) {
var $content = $(data).find('[data-type="prettyDate"]').prettyDate();
$('#mycontainer').append($content);
}
});
or have an helper function which you call
function prettify(data) {
return $(data).find('[data-type="prettyDate"]').prettyDate();
}
or even better hook into the ajax call so that it is done for all html content
There have been a number of cases where I needed certain code to execute after every AJAX call. I'm not sure if it's considered the "correct" solution but I simply decided to create my own wrapper method and use that whenever I needed to make an AJAX request. It typically looks something like this:
AJAXLoadData: function (url, data, successCallBack) {
$.ajax({
type: "GET",
data: data,
url: url,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
// Code I want to execute with every AJAX call
// goes here.
// Then trigger the callback function.
if (successCallBack) successCallBack(msg);
},
error: function (msg) {
alert("Server error.");
}
});
}
In my case this made it particularly convenient to create a javascript caching system for static HTML files.
You could incorporate this code into your ajax success callback function. When the ajax is done and you update your page, also run the code to prettify the dates.
This is one of the things .on() is for. (In the olden days, .live() would have been used.)

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.

how to make a jquery "$.post" request synchronous [duplicate]

This question already has answers here:
How can I get jQuery to perform a synchronous, rather than asynchronous, Ajax request?
(14 answers)
Closed 9 years ago.
I’ve been googling this and avoiding this error in my bug fix list for a long time now, but I’ve finally reached the end of the list, the last of which I have to make a function return true/false to state whether the validation has succeeded or not.
I'm using ajax to compare certain fields with those that are already in the db and by default the $.post() method does it's operations asynchronously.
I’m setting a variable inside the call onSuccess and the calling method doesn't get a response because of this, so all my js/jquery fails on pageLoad... I would prefer if I could still keep using the $.post method.
jQuery < 1.8
May I suggest that you use $.ajax() instead of $.post() as it's much more customizable.
If you are calling $.post(), e.g., like this:
$.post( url, data, success, dataType );
You could turn it into its $.ajax() equivalent:
$.ajax({
type: 'POST',
url: url,
data: data,
success: success,
dataType: dataType,
async:false
});
Please note the async:false at the end of the $.ajax() parameter object.
Here you have a full detail of the $.ajax() parameters: jQuery.ajax() – jQuery API Documentation.
jQuery >=1.8 "async:false" deprecation notice
jQuery >=1.8 won't block the UI during the http request, so we have to use a workaround to stop user interaction as long as the request is processed. For example:
use a plugin e.g. BlockUI;
manually add an overlay before calling $.ajax(), and then remove it when the AJAX .done() callback is called.
Please have a look at this answer for an example.
If you want an synchronous request set the async property to false for the request. Check out the jQuery AJAX Doc
From the Jquery docs: you specify the async option to be false to get a synchronous Ajax request. Then your callback can set some data before your mother function proceeds.
Here's what your code would look like if changed as suggested:
beforecreate: function(node,targetNode,type,to) {
jQuery.ajax({
url: url,
success: function(result) {
if(result.isOk == false)
alert(result.message);
},
async: false
});
}
this is because $.ajax is the only request type that you can set the asynchronousity for

jQuery: getJSON + SunlightLabs API help requested

I'm having trouble pulling a specific element from an API call using jQuery's getJSON function. I'm trying to use SunlightLab's congress API to pull specific info about legislators. In the example below I'm trying to pull a legislator's website:
$.getJSON("http://services.sunlightlabs.com/api/legislators.get.json?apikey=[api key]&lastname=Weiner&jsonp=?" , function(data) {
alert("hello from sunlight");
alert(data.response.legislator.website);
});
Using the above code, the first alert shows up but the second alert does not even occur. I understand that getJSON should be using JSONP in this instance, and I think I have that set up correctly, ending my URL with '&jsonp=?'.
Putting the URL in my getJSON function into a web browser gives me this:
?({"response": {"legislator":
{"website":
"http://weiner.house.gov/", "fax":
"202-226-7253", ... etc.
I'm a little thrown by the '?' showing up at the beginning of this, but if the first alert is showing up then the request must be succeeding...
The URL you're using is setting the JSONP callback to be equal to ?, which means its injecting a JavaScript function called ? with an argument of a JavaScript object. This is invalid. So, the request is succeeding, but the wrapper function you've defined isn't being called (and isn't valid).
You could change the URL so that its jsonp=callback (or some other handler function name), and then define a function called callback that handles an argument that expects the object.
One way to (automatically) trigger JSONP support in jQuery is to switch the key to be called 'callback' so that it signals to jQuery that you're doing a JSONP call. ie, callback=callback.
EDIT: As Drackir points out, jQuery provides a setting in $.ajax for letting it define it's own callback function name, but you need to signal to it that its a JSONP call by setting dataType: 'jsonp' in the $.ajax call.
The question mark is there because you specified the JSONP callback function to be ? in your query string (ie. &jsonp=?). Due to security concerns (specifically the same-origin policy) you cannot do an AJAX request to a site outside the same domain as the page you're on. To get around this, JSONP works by creating a script tag, with the SRC set to the URL of the script on the other site. This will load the external JavaScript file and run whatever code is there. Now, in order to link that external code with your JavaScript, the external API takes the name of a function to call (&jsonp=functionnametocall). The returned JavaScript calls that function and passes in the data it's trying to return as a JSON object as the first argument.
So, the reason you see the question mark when you go there is because you're passing a question mark to the jsonp query string parameter. jQuery will automatically convert the question mark in a url such as http://www.test.com/api/apikey=292929&callback=? to a uniquely named function. This is handled in the background by jQuery so you don't have to think about it.
Now, that said, I don't know if jQuery detects if the name of the callback parameter as being something other than callback=?. $.getJSON() however is a short form for the longer:
$.ajax({
url: url,
dataType: 'json',
data: data,
success: callback
});
I suggest you try using $.ajax() directly and set the jsonp setting equal to "jsonp". This tells the $.ajax() method that the query string parameter is called jsonp and not callback. So like this essentially:
$.ajax({
url: url,
dataType: 'json',
data: data,
success: callback,
jsonp:"jsonp"
});
More information: $.getJSON | $.ajax()
OK, OK, so it was a rather simple fix, adding a line to the the example given by #Drackir. The missing piece was 'cache: true' within the ajax settings. The final working code looked like this:
$.ajax({
url: 'http://services.sunlightlabs.com/api/legislators.get.json?apikey=[api key]7&lastname=Weiner',
dataType: 'jsonp',
cache: true,
jsonp: 'jsonp',
success: function(data) {
alert("hello from ajax") ;
alert(data.response.legislator.website);
}
});
I'm not sure why 'cache: true' is needed in this case. Thanks for the help.

When to use jQuery.ajax and when to use jQuery.post?

It seems, at the first glass, that we can use either of those. I'm wondering, however, when should we use one or the other, assuming a scenario where we can do the same thing with any of those two.
Thanks in advance,
MEM
jQuery.post is a shorthand method which calls jQuery.ajax.
If you don't need any functionality not supported by the shorthand, you might as well use it.
It's defined like this:
post: function( url, data, callback, type ) {
// shift arguments if data argument was omited
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = {};
}
return jQuery.ajax({
type: "POST",
url: url,
data: data,
success: callback,
dataType: type
});
},
The $.post is actually derived from $.ajax. You can use $.post when you want want to set the POST method in your request. $.ajax allows you to set both GET and POST request methods.
Using $.ajax allows you to set callbacks for failure, and completion, while $.post has callback only for success. Also, $.ajax allows to set a callback to be invoked before the sending of the request and set other useful parameters as timeout time , username or password if the target script needs authentication.
In short, $.post is a useful shortcut to use in the simpler situation, while $.ajax offers full control on the request.

Categories

Resources