ajax request rely on the previous one - javascript

I want to do something like this:
$.ajax({
url: SOMEWHERE,
...
success: function(data){
// do sth...
var new_url = data.url;
$.ajax({
url: new_url,
success: function(data){
var another_url = data.url;
// ajax call rely on the result of previous one
$.ajax({
// do sth
})
}
})
},
fail: function(){
// do sth...
// ajax call too
$.ajax({
// config
})
}
})
the code looks awful for me.
I wonder how to make it looks pretty. Some best practice?

I would consider breaking it up, maybe something like this.
function initialSuccessHandler(data) {
$.ajax({url:data.url, success:secondarySuccessHandler});
}
function secondarySuccessHandler(data) {
//do stuff
}
function initialFailHandler() {
$.ajax({...});
}
$.ajax({url:"whatever.com", success:initialSuccessHandler, fail: initialFailHandler});

There's not a whole lot you can probably do about it other than if the success function are similar (just need different URL's to new AJAX calls for example) you might be able to define a common function to call recursively, like this:
function do_something(data) {
// some logic
$.ajax({
url: data.url,
success: do_something(data);
fail: function (){
// handle failure
}
});
}

Use $.post instead of $.ajax that's lot easier and clean
$.post('yourAjaxUrl.com/index.html',(newVal:'val'), function(data) {
$.post('yourSecondAjaxUrl.com/index.html',{newVal1:data}, function(data) {
//do something
});
});
Or if you want to use GET request use like this.
$.get('yourAjaxUrl.com/index.html',(newVal:'val'), function(data) {
$.get('yourSecondAjaxUrl.com/index.html',{newVal1:data}, function(data) {
//do something
});
});

Other answers are mostly fine too as using functions in a lot of case will definitely help your code. The problem of your function is that it's doing to much things all in once. Decreasing the complexity of the function will help a LOT (separating different action in different functions).
There's some good training videos of Bocoup here which can help you decrease a function complexity: http://training.bocoup.com/screencasts/
Although, a basic answer to the callback inferno:
You could use jquery Deffered who do a good job in certain case by preventing the "indentation pyramid of doom". (But won't decrease the complexity of your function)
$.ajax({
url: SOMEWHERE
})
.pipe(function() {
// First success callback
return $.ajax({
url: new_url
});
}, function() {
// First error callback
$.ajax({
// config
});
// we ain't returning anything so this end here.
})
.done(function( data ) {
// Second success callback
var another_url = data.url;
// ajax call rely on the result of previous one
$.ajax({
// do sth
})
});
Deferred can fit in a whole lot more of context, and learning about them is really useful. That's only the basic idea behind them.
Hope this help!

Related

Nesting ajax requests makes code hard to read

I usually like to organize my code so that one function fires a bunch of other
functions, like this:
/**
* GET MESSAGES:
*/
$(function() {
$.ajax({
url: '/messages',
method: 'GET',
dataType: 'json',
success: function(messages) {
if (messages.length > 0) {
keyedMessages = keyFork(messages);
reversedMessages = reverse(keyedMessages);
crushedMessages = crush(reversedMessages);
getFriendships(messages, crushedMessages);
}
mail.template.airmail();
}
});
});
However, if I need to do a second Ajax request inside one of the nested
functions I can't return the data because of the scope of the Ajax request
and it makes my code inconsistent and hard to follow, sort of broken up all over the place. For example, if one of the functions
invoked above fires a second Ajax request for friendships anything I write
after that will be broken from the communication chain due to the request and it seems impossible to return anything:
/**
* GET FRIENDSHIPS:
*/
function getFriendships(messages, crushedMessages) {
$.ajax({
url: 'friendships',
method: 'get',
dataType: 'json',
success: function(friendships) {
addKey(crushedMessages, friendships);
filteredCrushedMessages = filterUnconfirmedSender(crushedMessages);
filteredCrushedMessages.forEach(function(filteredCrushedMessage) {
mail.sidebar.builder.messengers(filteredCrushedMessage);
});
mail.snailMail.onload();
}
});
}
If I try to return the data it doesn't work. Consequently I'll have to
continue invoking functions inside the nested request, every time I need to make another nested ajax request it breaks the chain. This makes my
code very hard to read. Are there any solutions to this problem or is
code that uses Ajax requests just hard to read?
You could store the data on a DOM element, then use jQuery Custom Events to get it done.
There's even support for passing arguments to your event handler:
https://learn.jquery.com/events/introduction-to-custom-events/#naming-custom-events
If I try to return the data it doesn't work.
Not appear jQuery promise returned from either function at Question ?
Try utilizing return statement , $.when.apply(this, arrayOfPromises) to return array of jQuery promise object from getFriendships
function getFriendships(messages, crushedMessages) {
return $.ajax({
url: 'friendships',
method: 'get',
dataType: 'json',
success: function(friendships) {
addKey(crushedMessages, friendships);
filteredCrushedMessages = filterUnconfirmedSender(crushedMessages);
mail.snailMail.onload();
return $.when.apply($
, filteredCrushedMessages.map(function(filteredCrushedMessage) {
return mail.sidebar.builder.messengers(filteredCrushedMessage);
})
);
}
});
}
// e.g.,
getFriendships(messages, crushedMessages)
.then(function success() {
console.log(arguments)
}, function err(jqxhr, textStatus, errorThrown) {
console.log(errorThrown)
})

Nested AJAX Calls using .done

I'm fairly new to AJAX, but working on a project that requires an ajax call to validate a specific value, then make another ajax call if the first returns the expected value. I am trying to implement the .done/.fail model, but can't find a way to prevent both calls from happening simultaneously, rather than once the first call is done and successful.
The following code will call the ajaxCall function twice, but concurrently rather than consecutively. I have researched a ton of code, including Nested AJAX Calls, jQuery getting rid of nested ajax functions, and $.when.done callback isn't working, but none seem to fit my exact scenario, or maybe I just don't understand the code. Either way, I haven't been able to find a solution, and any help will be much appreciated!
var xReturn = ajaxCall("1");
xReturn.done(function(msg){
console.log("callback "+msg+" successful");
// if successful, place second call
if(parseInt(msg)==1)
xReturn = ajaxCall("2");
});
function ajaxCall(mop){
return $.ajax({
url: "getItem.php",
type: "POST",
data: {code: '<?php echo $code; ?> ', op:mop}
});
}
It seems like promises may be the way to go, but I can't wrap my head around how to use them in this scenario. Thanks in advance for any pointers in the right direction.
Update:
I ran through a battery of tests with different results. For my final test last night, I placed another console.log(msg); directly after ajaxCall("2"); Each time the resulting msg was always "1", leading me to believe the calls were not happening properly. This result tells me that xReturn.done(function(msg)... is only being called once, but I thought it would be called with each ajax call.
With this new information, I will perform additional testing tonight and report back.
Thanks
You need to bind a .done() method to each promise. xReturn.done() binds a function to that promise.
When you do xReturn = ajaxCall("2");, you are replacing xReturn with a different object. This object does not have a .done() method bound to it.
You need to bind .done() to each promise, that doesn't happen automatically.
var xReturn = ajaxCall("1");
// This binds the callback to this *specific* promise
xReturn.done(ajaxDone);
function ajaxCall(mop){
return $.ajax({
url: "getItem.php",
type: "POST",
data: {code: '<?php echo $code; ?> ', op:mop}
});
}
function ajaxDone(msg){
console.log("callback "+msg+" successful");
// if successful, place second call
if(parseInt(msg)==1){
xReturn = ajaxCall("2");
// Bind a callback to this *new* object
xReturn.done(ajaxDone);
}
}
There are multiple ways to go about this problem.
You could simply call the second ajax call from the success of the first. Something on the following lines
function ajaxCall(mop){
$.ajax({
url: "getItem.php",
type: "POST",
data: {code: '<?php echo $code; ?> ', op:mop}
}).done(function(msg) {
console.log("First call is done. Received data as ", msg);
if(parseInt(msg)==1) {
$.ajax({
//Repeat Options
}).done(function(newMsg)) {
console.log("We're done");
};
}
});
}
}
If you do want to use the .done/.fail model, you could try using $.when.
Here is a working fiddle that does consecutive calls using the same function.
function ajaxCall(mop){
return $.ajax({
url: "/echo/json/",
type: "POST",
data: {
json: $.toJSON({data: mop}),
delay: Math.floor(Math.random()*4)
}
});
}
$.when(ajaxCall("1")).done(function(data) {
console.log("Done with first call. About to call second");
if(data /* and add whatever conditions you need to call the next function */) {
ajaxCall("2");
}
});
Try it like this.
ajaxCall("1");
function ajaxCall(mop){
$.post( "getItem.php", {code: '<?php echo $code; ?> ', op:mop})
.done(function( msg) {
console.log("callback "+msg+" successful");
if(parseInt(msg)==1)
ajaxCall("2");
});
}
And also you can use these with previous code
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "finished" );
How about that:
var xReturn1 = ajaxCall("1"),
xReturn2 = ajaxCall("2");
$.when(xReturn1, xReturn2).done(function( a1, a2 ) {
var data1 = a1[0], data2 = a2[0];
console.log("Both done");
});

Jquery stop function

I have a jquery function like this:
function get()
{
$.ajax({
url: 'get.php',
success: function(data) {
$('#get').html(data);
$('#get').fadeIn(2000);
setTimeout(posts,2000);
}
});
}
get();
I want to stop this function when i click on a certain element in a webpage, how would i do this.
Thanks
Set a variable for your AJAX request.
var getajax;
function get() {
getajax = $.ajax({
......
});
}
When you want to abort it, simply
getajax.abort();
In a situation where you may not be able to globaly define all of your .ajax() call variables (as shown by another answer by #uzyn), this might be a suitable solution.
You could simply wrap your success callback with a flag indicating whether you want to cancel the result.
var ajax_canceled = false;
function get(){
$.ajax({
url: 'get.php',
success: function(data) {
if (!ajax_canceled){
//...
}
}
});
}
get();
$("#cancel_ajax").on('click',function(){
ajax_canceled = true;
});

How to use jQuery ajax data to variable

I have the following javascript code:
function initSite(){
var site;
$.getJSON(www+'init/initSite', function(data) { site = data; });
}
$(document).ready(function(){
var site = initSite();
console.log(site);
}
which returns undefined... how can i store the json object that i recieve in the site variable so i can use it later?
EDIT:
This seem to work but im not sure if its correct to use this solution
var site = null;
$.ajax({
url: www+"init/initSite",
async: false,
dataType: 'json',
success: function (data) {
site = data;
}
});
console.log(site);
of course you got undefined because your function doesn't return anything and the ajax call is also asynchronous, so you have to wait the server response. Since $.ajax (and shortcuts) returns a promise you can do this task using deferred
function initSite(){
return $.getJSON(www+'init/initSite');
}
$(document).ready(function(){
$.when(initSite()).done(function(data) {
/* continue here the code execution, e.g. call another function */
doAllTheRemainingWorkWith(data)
});
}
as you can see this code is short and easy to read
function initSite(onSuccess){
$.getJSON(www+'init/initSite', onSuccess);
}
$(document).ready(function(){
initSite(function(data){
var site = data;
// initialize your code.
});
}
The problem is just a miss concept:
getJSON is an async call, and the site = data; will only happen way after the DOM is ready.
in order for you to make everything work the way it should, your initialization needs to start from your async call result and never before, for example:
// no need to wait for DOM ready to call `initSite`
initSite();
function initSite() {
$.getJSON(www+'init/initSite', function(data) {
initialization(data);
});
}
function initialization(site) {
// initialize all the things that need to be done
console.log(site);
}
$(document).ready(function(){
// do other stuff, for example show a loading message/image
}

Ajax jquery synchronous callback success

I have this function that makes an ajax call. I'm describing the problem in the last chunk of code comments.
function doop(){
var that = this;
var theold = "theold";
var thenew = "thenew";
$.ajax({
url: 'doop.php',
type: 'POST',
data: 'before=' + theold + '&after=' + thenew,
success: function(resp) {
if(resp == 1) {
$(that).siblings('.theold').html(thenew);
}
}
});
// I have some code here (out of the ajax) that **further** changes
// the .theold's html beyond what it was changed inside ajax success
// but the change depends on whether the resp (inside the success
// function) returned 1 or not, so this code out here depends on the ajax
// so it looks like I have to turn this ajax call into a sync ajax
return false;
}
Based on the problem as described in the code comments, what changes are best for this situation?
You need to set async: false for synchronous requests like this:
function doop(){
var that = this;
var theold = $(this).siblings('.theold').html();
var thenew = $(this).siblings('.thenew').val();
$.ajax({
async: false,
url: 'doop.php',
type: 'POST',
data: 'before=' + theold + '&after=' + thenew,
success: function(resp) {
if(resp == 1) {
$(that).siblings('.theold').html(thenew);
}
}
});
// some other code
return false;
}
see here for details
Either set the Ajax call to synchronous as stefita pointed out, or just move your code into the success callback. Why can't you do this? Even if it's another Ajax call it still can be done - you can nest them. With the information given by you so far (I can't see the problematic code, nor I have enough domain knowledge about your project) I don't see a problem, really.
I prefer to use callback to do the job because it achieves exactly the same result without actually making it synchronous. I use success:callback and then pass in the callback as a parameter.
function getData(callback) {
$.ajax({
url: 'register/getData',
data: "",
dataType: 'json',
success: callback
});
}
I then call this function like this:
getData(function(data){
console.log(data); //do something
});

Categories