Do action after another ajax function ends - javascript

I'm searching a solution for this:
I have a function that updates the content of a table in my application.
function prev_update(cli_id){
$("#list").empty();
$("#list").append("<tr><td colspan=11><img src='images/loading.gif' alt=loading title=loading /></td></tr>");
$.ajax({
type : 'POST',
url : 'json/get.php?t=2&id='+cli_id,
dataType : 'json',
encode : true
})
.done(function(data) {
$("#list").empty();
if ((data)["prev_list"]) {
$.each((data)["prev_list"], function( i, val ) {
$( "#list" ).append(val);
});
$("#edit").hide("slow");
} else {
$("#list").append("<tr><td colspan=11> </td></tr>");
}
});
};
In another function I'm updating a row of a table, when I finish to edit the content of a row of the table i launch a similar function but in the .done row I call the prev_update function and AFTER this is finished I have to push a button in the updated table content, for review the modifications...
Here's the code:
$("#prev_mod").on("click",(function( event ) {
$('#loading_img').css('display','inline');
header_print();
$.ajax({
type : 'POST',
url : 'json/post.php?mod='+$('#prev_id').val(),
data : $("#form_sog").serialize(),
dataType : 'json',
encode : true
})
.done(function(data) {
if ((data)["success"]===false) {
$('#form_edit').hide('slow');
prev_update();
$('#edit_'+$('#prev_id').val()).click();
});
});
}));
I have to wait when prev_update() function ends then click the button because the button is in the table that is updating.
I tried to use also deferred object but it doesn't works (maybe for my error).
I can't edit the function prev_update because it's used by other functions.

Instead of .done you can use .then to organize your code. This is because .then can be chained
Not tested but it can be like this
function prev_update(cli_id){
$("#list").empty();
$("#list").append("<tr><td colspan=11><img src='images/loading.gif' alt=loading title=loading /></td></tr>");
$.ajax({
type : 'POST',
url : 'json/get.php?t=2&id='+cli_id,
dataType : 'json',
encode : true
})
.then(function(data) {
$("#list").empty();
// rest of code
}).then(function(data) {
if ((data)["success"]===false) {
// rest of code
};
});

If you want to know when everything inside of prev_update() is done, you HAVE to modify it to keep track of the async operations in it and to return a promise. Then, the caller can use that returned promise to know when things are done.
So, inside of prev_update(), the two async operations are the ajax call and the .hide() animation. The hide animation occurs inside of the completion handler for the ajax operation. So, if you change .done() to .then(), we can chain together these promises and return a single promise that will tell the caller when everything is done.
jQuery has a .promise() method that will get us a promise that is linked to any jQuery animation so if we just get the promise for the animation, we can return it and it will chain to the parent promise. If there was no animation, then we can just return nothing and the promise chain will continue.
This does not change the functionality of prev_update() at all - it just returns a promise that tracks its completion (when you were previously not returning anything).
That can work like this:
function prev_update(cli_id){
$("#list").empty();
$("#list").append("<tr><td colspan=11><img src='images/loading.gif' alt=loading title=loading /></td></tr>");
return $.ajax({
type : 'POST',
url : 'json/get.php?t=2&id='+cli_id,
dataType : 'json',
encode : true
}).then(function(data) {
var p;
$("#list").empty();
if ((data)["prev_list"]) {
$.each((data)["prev_list"], function( i, val ) {
$( "#list" ).append(val);
});
p = $("#edit").hide("slow").promise();
} else {
$("#list").append("<tr><td colspan=11> </td></tr>");
}
// return promise if there was one
return p;
});
};
So, then you can use this in your other code like this:
$("#prev_mod").on("click",(function( event ) {
$('#loading_img').css('display','inline');
header_print();
$.ajax({
type : 'POST',
url : 'json/post.php?mod='+$('#prev_id').val(),
data : $("#form_sog").serialize(),
dataType : 'json',
encode : true
}).then(function(data) {
if ((data)["success"]===false) {
$('#form_edit').hide('slow');
prev_update().then(function() {
// apply click when everything in prev_update() is done
$('#edit_'+$('#prev_id').val()).click();
});
});
});
}));

Related

Calculating the Time of an ajax Response and use that time in SetTimeout function

I am trying to get the response time of an ajax request and use it in a setTimeout() function, this function displays a loader that is suppose to keep loading until we get the response.
Here's my function :
$("#recalculer").click(function(){
ajax_call();
setTimeout(function()
{
$("#divgris").fadeTo(0,1);
$("#loadingdiv2").hide();
}, 5000);
});
And here's my ajax request :
function ajax_call()
{
var resultat;
var duree_souhaitee= $("#duree").val();
var apport_personnel= $("#apport").val().replace(/\s+/g, '');
var prix_achat_bien=$("#prix").val().replace(/\s+/g, '');
$.ajax({
type: "POST",
url: "/iframe/rest-assurance",
data : {
"duree_souhaitee" : duree_souhaitee,
"apport_personnel" : apport_personnel,
"prix_achat_bien" : prix_achat_bien
},
dataType: 'json',
xhrFields: {
withCredentials: true
},
async: true,
beforeSend: function(){
$("#actualiserAssurance").hide();
},
success: callback_assurance
});
}
For now i set a time of 5000 but i need to replace it with the ajax response time, how can I achieve that ?
I use always:
$("#loadingdiv2").show();
$.ajax(
...
).always(function(){ $("#loadingdiv2").hide(); });
If you want to separate it from the Ajax call I would use a custom event.
$("#recalculer").click(function(){
ajax_call();
});
$("body").bind('custom.ajaxStart', function(){ $("#loadingdiv2").show(); });
$("body").bind('custom.ajaxStop', function(){ $("#loadingdiv2").hide(); });
function ajax_call(){
$('body').trigger('custom.ajaxStart');
$.ajax(..).always(function(){ $('body').trigger('custom.ajaxStop'); });
}
The always callback is triggered even on a 404, relying on timing never works well for me.
Using an event gives you the flexibility of calling the loading deal, from anywhere.
Meaby the you can use:
console.time(label);
and
console.timeEnd(label);
more info can be found here.
Goodluck!
use
var afterfnc = ()=>{
$("#divgris").fadeTo(0,1);
$("#loadingdiv2").hide();
}
and then set
callback_assurance = afterfnc
in ajax call

How to work with JSONP to call back the function?

I am trying to communicate with a server using JSONP call back.
Here is my code
$('.icwsDownloadRecording').click(function(){
var id = $(this).attr('data-recordingid');
$.ajax({
type: 'GET',
url: 'http://example.com/Default2.aspx',
data: {'ID': id},
dataType: 'jsonp',
cache: false,
timeout: 40000,
crossDomain:true,
jsonp: "MyCallbackFunction",
});
});
function MyCallbackFunction(data)
{
//process data further
console.log(data);
if(!data || data.url.length < 5){
return;
}
var $preparingFileModal = $("#preparing-file-modal");
$preparingFileModal.dialog({ modal: true });
$.fileDownload( data.url, {
successCallback: function (url) {
$preparingFileModal.dialog('close');
},
failCallback: function (responseHtml, url) {
$preparingFileModal.dialog('close');
$("#error-modal").dialog({ modal: true });
}
});
return false; //this is critical to stop the click event which will trigger a normal file download!
}
The issue here is that I keep getting this message in the console
ReferenceError: MyCallbackFunction is not defined
I do have this defined as you can see in my code above
The server respond looks like this
MyCallbackFunction("{'URL': 'http:\/\/example.com:8106\/ghjgj3835396265336634646562363030303122226D616C686179656B22535353557DBE0C305645E2DE110AA1D7F8792E96A3'}");
how can I correct this issue?
EDITED
This is my code after Quentin Answer , this is my new code
$(function(){
$('.icwsDownloadRecording').click(function(){
var id = $(this).attr('data-recordingid');
$.ajax({
type: 'GET',
url: 'http://example.com/Default2.aspx',
data: {'ID': id},
dataType: 'jsonp',
timeout: 40000,
success: function(data){
//process data further
console.log(data);
if(!data || data.url.length < 5){
return;
}
var $preparingFileModal = $("#preparing-file-modal");
$preparingFileModal.dialog({ modal: true });
$.fileDownload( data.url, {
successCallback: function (url) {
$preparingFileModal.dialog('close');
},
failCallback: function (responseHtml, url) {
$preparingFileModal.dialog('close');
$("#error-modal").dialog({ modal: true });
}
});
return false; //this is critical to stop the click event which will trigger a normal file download!
}
});
});
});
Unless you have all of that code wrapped in another function, that should work.
Using a hardcoded function name is bad practise though.
Update:
$(function(){
You do have all that code wrapped in another function.
Remove this:
jsonp: "MyCallbackFunction",
Replace it with:
success: MyCallbackFunction
Or you could put an anonymous function expression there instead (as you have done in your edit)
Let jQuery generate a unique function name (which protects you from race conditions) and allow the server to use the callback query string argument to determine what function name to use.
MyCallbackFunction is in the same scope as the ajax call, so it will be available to the function (which can copy it to a suitably named global).
After you fix that, you have an additional problem:
MyCallbackFunction("{'URL':
Your response is JSON encoded in a JavaScript string, but you are trying to treat it as a JavaScript object.
Either:
Fix the server so it doesn't stringify the JSON or
Run the first argument through JSON.parse
crossDomain:true,
Remove that. It doesn't do anything here. (All it does is, when using XHR (which you aren't using) to the same origin (which you aren't targeting), suppress the custom headers that aren't typically allowed on a cross-origin request so that you can perform an HTTP redirect to a different origin).
cache: false,
That's the default for JSONP requests. Including it is pointless.
return false; //this is critical to stop the click event which will trigger a normal file download!
If you want to stop the click event, then you need to return false from the click event handler function (not the Ajax success handler).
You can't wait until the Ajax function has run and got a response before doing that. Ajax is asynchronous.

How to append first, then run ajax in jquery?

I want to append first, then run ajax to update the data and then do the search. See the code below. I want to put a code like if append, then run $.post. How can I do that in jquery, thanks?
$('<span />', { class: 'result_tag', text: href }).insertBefore($input);
$('.result_tag').append(' ');
//make sure append first and then run .post
$.post("member_search.php", {
search_text: $(".result_tag").text()
}).done(function()
{
$.post("member_search.php", {
search_text: $(".result_tag").text()
},
function(data){
$("#find_members").html(data);
});
});
The $.post() function returns a promise. You can call the done() function on this promise. The done() function takes a callback function which will be executed after the post to the server is done:
$.post("update.inc.php", {
tag : $(this).closest("a").text(),
users_id : $("#users_id").val()
}).done(function(){
// your second post goes here
});
You can use $.ajax and its Event beforeSend like this:
$.ajax({
url: "http://fiddle.jshell.net/favicon.png",
data: 'search_text='+$(".result_tag").text(),
beforeSend: function( xhr ) {
$('.result_tag').append(' ');
}
})
.done(function( data ) {
//now do your other ajax things
});
Hope this will help you.
More Details are given in jQuery DOC

nested $.ajax in inside $.ajax - very strange issue

Let's start from here - I have defined base setting for all future AJAX-requests, like this
$.ajaxSetup({
beforeSend : function(){
$("#ajax-loader").dialog({
modal : true
});
},
complete : function(){
$("#ajax-loader").dialog("hide");
}
});
Now, I have a form where my users can upload their bio and pictures. When a form is valid, then I allow to upload their pictures. It works this way:
$("#send").click(function(e){
e.preventDefault();
$.ajax({
data : $("#bio-form").serialize(),
url : "/validate.ajax",
success : function(response) {
// If AJAX-validator returns "1" then a form is valid
if (response == "1"){
// Now I start to upload photos, like
// this
var formData = new FormData(document.getElementById('upload-form'));
$.ajax({
processData : false,
contentType : false,
cache : false,
data : formData,
success : function(response) {
alert(response);
}
});
}
}
});
});
The problem
Once ajax-uploading starts, I expect a $("#ajax-loader") to be showed. On complete this should be closed automatically according to the settings I defined in $.ajaxSetup.
BUT...
It appears and disappears right after 1 sec on file uploading. I know that ajax request isn't completed, because I get successfuly message after 1-2 mins (that photos uploaded).
I tried to change async: false and it started to work as expected === a modal appears when uploading files to server and disappers when done:
data : formData,
async : false,
processData : false,
Question
Is it possble to do the same when async : true is set to its default mode(true)? I don't want a browser to be frozen when uploading in progress!
As you've discovered, Ajax is an asynchronous technology - meaning it runs on its own schedule
Making Ajax synchronous causes all sorts of problems (using async:false actually causes the browser to freeze whilst the request is performed)
There are several issues I'd mention you may want to fix:
Why Nested Ajax?
Nesting Ajax requests, in this current state of the web, is, in my opinion, bad practice. It generally means you've got something wrong with your system. Concurrent requests are fine - but nested I'd avoid like the plague
Ajax Callbacks
If you can get your Ajax requests down to a single entity, I'd look at using Ajax Callbacks to create your desired result
Ajax callbacks work by using Ajax as part of a function, where the success & error callbacks are handled by several differnt parts of your parent function. Here's an example:
function create_modal(o){
fetch_modal(o.ajax, function(data){
//do success stuff here
}, function(data){
//do error stuff here
});
}
function fetch_modal(link, success, error) {
$.ajax({
url: link,
success: function(data) { success(data); },
error: function(data) { error(data); }
});
}
The problem is ajaxSetup. You have to follow enable/disable method on uploading photo. Let me clearup the understanding. You want to show the loader to intimate the user that he/she has to wait until validation process finishes. Once the validation get success you are starting to upload file. While uploading file, you want to allow the user interact with page.
To achieve this you have to do as follows,
function ajaxSetup(mode) {
var options = {};
if (mode === "on") {
options = {
beforeSend : function() {
$("#ajax-loader").dialog({
modal : true
});
},
complete : function() {
$("#ajax-loader").dialog("hide");
}
};
} else {
options = {
beforeSend : function() {
},
complete : function() {
}
};
}
$.ajaxSetup(options);
}
And Make your ajax request as follows,
ajaxSetup("on");
$("#send").click(function(e) {
e.preventDefault();
$.ajax({
data : $("#bio-form").serialize(),
url : "/validate.ajax",
success : function(response) {
// If AJAX-validator returns "1" then a form is valid
if (response == "1") {
// Now I start to upload photos, like
// this
var formData = new FormData(document.getElementById('upload-form'));
ajaxSetup("off"); //Here second-time seem-less displaying of loader will be avoided.
$.ajax({
processData : false,
contentType : false,
cache : false,
data : formData,
success : function(response) {
alert(response);
}
});
ajaxSetup("on");
}
}
});
});
Note: I am not tested code. Please make sure, if any syntax or typo error.

values won't get updated in a function because of a ajax call

I'm writing a javascript function that should change the view of a postcard depending on which case is selected.
My problem is that the old values of the object "m_case" is getting used. If I press the button with class "case-btn" twice I get the right case selected in my postcard view. But I want it to be triggered when I press the button once.
I guess I have to do something like a callback function in the m_case.setCase() function call, but I can't get it working,
$('.case-btn').on('click', function() {
remove_active_state_from_cases();
m_case.setCase($(this).data('case'));
// Changes the view of the postcard
m_postcard.changeBackground(m_case.getPhoto());
m_postcard.changeMessage(m_case.getMessageText());
m_postcard.changeFullName(m_case.getFullName());
m_postcard.changeCountry(m_case.getCountry());
$(this).toggleClass('active');
});
The setCase() function
this.setCase = function(id) {
// Set ID
this.setID(id);
var that = this;
$.ajax({
url: 'get_case_by_id.php',
type: 'get',
dataType: 'json',
data: {id: that.getID() },
success: function(data) {
if(data.success) {
that.setFirstName(data.first_name);
that.setFullName(data.full_name);
that.setAdress(data.adress);
that.setCountry(data.country);
that.setStamp(data.stamp);
that.setPhoto(data.photo);
that.setSummary(data.summary);
that.setStory(data.story);
that.setMessageText(data.message_text);
that.setDefaultMessageText(data.default_message_text);
that.setMessageImg(data.message_img);
} else {
console.log('failure');
}
}
EDIT The problem might be in my AJAX call, I have to wait till the ajax have been called. but how do I continue the first flow when my Ajax is done and not before?
SOLUTION
I made it working by adding a callback parameter and calling that function in the ajaxs complete function.
$('.case-btn').on('click', function() {
remove_active_state_from_cases();
var that = this;
m_case.setCase($(this).data('case'), function() {
m_postcard.changeBackground(m_case.getPhoto());
m_postcard.changeMessage(m_case.getMessageText());
m_postcard.changeFullName(m_case.getFullName());
m_postcard.changeCountry(m_case.getCountry());
$(that).toggleClass('active');
});
});
// Sets the whole case from an id.
this.setCase = function(id, callback) {
// Set ID
this.setID(id);
var that = this;
$.ajax({
url: 'get_case_by_id.php',
type: 'get',
dataType: 'json',
data: {id: that.getID() },
success: function(data) {
if(data.success) {
that.setFirstName(data.first_name);
that.setFullName(data.full_name);
that.setAdress(data.adress);
that.setCountry(data.country);
that.setStamp(data.stamp);
that.setPhoto(data.photo);
that.setSummary(data.summary);
that.setStory(data.story);
that.setMessageText(data.message_text);
that.setDefaultMessageText(data.default_message_text);
that.setMessageImg(data.message_img);
} else {
console.log('fail big time');
}
},
complete: function() {
callback();
}
});
}
Your m_postcard.changeBackground and other calls should be in the success callback, or in another function that is called from the success callback, as those values aren't set till the async ajax call is done.
With the way your code is now the m_postcard.changeBackground and other calls are called immediately after your setCase function is done executing. This means your methods are executed before the data has arrived from the server
While the ajax is processing you probably should show a loading message on the screen to let the user know they have to wait till the processing is done. Show the message before calling the .ajax call and hide it in the success/error callbacks.
Any changes to the site content should be done from the success callback, ie changing active states, changing content, etc.

Categories

Resources