I have a code where basically I've created a function in which, by the help of jQuery ajax, I fetch a value and set it as a data attribute of an element.
then after calling the function, I store the data value in a variable.
But the problem is that I don't want to execute any code before the ajax function completes.
JS
function load_data(){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar')
}
})
}
load_data(); //let the function set data first
console.log($('.element').data('foo')) //then execute this line
How to achieve this?
You can receive a callback function in load_data and execute it in the success function. Something like this:
function load_data(callback){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar');
callback();
}
})
}
load_data(function() {
console.log($('.element').data('foo'));
});
Of course, if this is your real scenario, you could simply put console.log($('.element').data('foo')); directly inside the success function.
You can use, Async-Await. https://javascript.info/async-await
async function load_data(){
await $.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar')
}
});
console.log($('.element').data('foo')) //then execute this line
}
load_data(); //let the function set data first
Also, you can do it using callback as well.
function load_data(callback){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar');
callback();
}
})
}
function doItLater(){
console.log($('.element').data('foo')) //then execute this line
}
load_data(doItLater); //let the function set data first
You can pass the data as a parameter to doItLater for getting data to your current scope.
try using .done()
load_data()
.done(function(dataResponse){
console.log($('.element').data('foo')) //then execute this line
}); //let the function set data first
the code inside will run after a your ajax call is responded and dataResponse has any response from you ajax call
This is not directly possible due to Asynchronous ajax call.
There are two ways to achieve what you want
1.
Create a function/s for the code you want to execute after successful ajax request
Call that function/s from ajax success block
Eg.
function load_data(){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar');
console.log($('.element').data('foo')); // Your code goes here
}
})
}
2
Return $.ajax in load_data function
And use .then or .done function for load_data itself
Eg.
function load_data(){
return $.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar')
}
})
}
load_data().done(function() {
console.log($('.element').data('foo')); // Your code goes here
});
However, .done and .then do not behave the same. In particular, if a standard promise callback returns another promise, this will delay the resolution of all later promises. jQuery's then behaves like this, but done does not. It is not possible for a done callback to delay the resolution of later callbacks.
Ajax is asynchronous. So, you have to listen for success event and do your stuff. You might achieve something similar to your needs by using await/async
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/async_function
const load_data = async () => {
return await fetch('https://exmaple.com');
}
load_data();
$('.element').attr('data-foo', 'bar')
You could just put the console log inside of the success callback, after you set the element attribute.
If you don't want the console log written inside load_data (maybe you want to make load_data reusable, without the console log), you could put the console log in a callback function and pass the callback to load_data and call it in the ajax success function:
function load_data(cb){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar')
cb();
}
})
}
function callback() {
console.log($('.element').data('foo'))
}
load_data(callback);
Another option is to set async: false in the ajax settings object, which would prevent following code from being executed before the ajax function resolves, but this is not generally a recommended practice.
with this:
$.when(load_data()).then(console.log($('.element').data('foo')));
Related
I have a custom loop that needs to execute a function before going into the next iteration. This is the code:
function customIteration(arr, i)
{
if (i==arr.length) return;
var message = arr[i];
jQuery('#stepTwo #num1StepTwo').html('Expires: ' + $num1);
jQuery('#stepTwo #num2StepTwo').html(jQuery(message).find('.num2').text());
jQuery('#stepTwo #num3StepTwo').html(jQuery(message).find('.num3').text());
i++;
jQuery.when(mySpecialFunction()).then(customIteration(arr, i));
}
mySpecialFunction():
function mySpecialFunction(){
return jQuery.ajax({
url: "https://api.site.com/customurl",
dataType: "jsonp",
data: { data1: $data1, data2: $data2 },
success: function (data) {
...some code...
},
error: function (e) {
...some other code...
}
});
}
problem is, I see in Fiddler that the url is being hit immediately by all the instances of the loop above, without waiting to get a response from the ajax code inside mySpecialFunction(). This is of course messes up the results I should get.
Try using .done()
in fact,
.done() has only success callback.
.then() has both success and fail callbacks.
As of jQuery 1.8, the deferred.then() method returns a new promise that can filter the status and values of a deferred through a function, replacing the now-deprecated deferred.pipe() method.
The deferred.done() method accepts one or more arguments, all of which can be either a single function or an array of functions.
Since deferred.done() returns the deferred object, other methods of the deferred object can be chained to this one, including additional .done() methods. When the Deferred is resolved, doneCallbacks are executed using the arguments provided to the resolve or resolveWith method call in the order they were added.
Try it using .done() and a recursive function, should be easier to implement and understand.
Like this:
(function recursive(arr,i){
jQuery.ajax({
url: "https://api.site.com/customurl",
dataType: "jsonp",
data: { data1: $data1, data2: $data2 },
success: function (data) {
...some code...
},
error: function (e) {
...some other code...
}
}).done(function(data){
var message = arr[i];
jQuery('#stepTwo #num1StepTwo').html('Expires: ' + $num1);
jQuery('#stepTwo#num2StepTwo').html(jQuery(message).find('.num2').text());
jQuery('#stepTwo #num3StepTwo').html(jQuery(message).find('.num3').text());
if(i!=arr.length){
recursive(++i);
}
}); /// End done
})(0); ///End recursive function
What this does is make sure your single iteration ends before calling itself up again and continuing iterating.
So basically your function is calling itself when it's done with a single iteration, and continues until everything has been iterated, then stops.
I am having problems using variables inside functions. So I have code:
functions.js:
function foo (callback){
$.ajax({
type:"POST",
url:"ajax/companyInfo.php",
data: dataString,
success: callback
});//end ajax
alert (dada);
}
function mycallback (result){
array=result.split('/');
alert(dada);
}
invoice.php:
var array = [];
var dada="";
$('#next1').on('click', function(){
dataString='company= '+$(this).closest('.inside').find('select').val(); // this is just for ajax
resizeall($(this), 200, 100); //this is function that works and has no problem
foo(mycallback);
console.log(array);
});//end on click function
It says:
Uncaught ReferenceError: dada is not defined functions.js:41
Uncaught ReferenceError: dada is not defined functions.js:46
I think it's might be related to closures isn't it. What is going wrong?
Kind of hard to debug since I can't see all of the invoice.php or functions.js
The line numbers you report (41 and 46) indicate that there is more to functions.js then
what you pasted.
But I'll give a hack you could try
invoice.php
var array = [];
window.dada="";
$('#next1').on('click', function(){
dataString='company= '+$(this).closest('.inside').find('select').val(); // this is just for ajax
resizeall($(this), 200, 100); //this is function that works and has no problem
foo(mycallback);
console.log(array);
});//end on click function
functions.js
function foo (callback){
$.ajax({
type:"POST",
url:"ajax/companyInfo.php",
data: dataString,
success: callback
});//end ajax
alert (window.dada);
}
function mycallback (result){
array=result.split('/');
alert(window.dada);
}
Here is what your setup should look like.
function getCompanyInfo(companyName) {
return $.post("ajax/companyInfo.php", {
company: companyName
}).then(function (rawData) {
return rawData.split("/");
});
}
$('#next1').on('click', function() {
var companyName = $(this).closest('.inside').find('select').val();
resizeall($(this), 200, 100);
getCompanyInfo(companyName).done(function (array) {
console.log(array);
// everything else you want to do with the array goes here
});
});
Read up on jQuery Deferreds to find out what .then() and .done() do.
Final tip: If you want to update data on the server, use a POST request. If you want to fetch information from the server, use a GET request. The .post() in my code above is there because you used it in your code. It's semantically wrong and you really should change it to .get().
I am writing a function that makes a http call to a web service, grabs some data and calls another function based on this data. If the service is down, the second function should not be called. I thought the obvious way to do this would be to write $.when(func1()).done(func2); but this will trigger func2 even when the request is aborted. I realise that I can do a workaround by calling func2 within the success function of func1's $.getJSON method, but I would like to use the deferred syntax if possible. Can anyone suggest how to handle this in a way that is consistent with the deferred object syntax?
function checker() {
console.log("in checker");
$.getJSON("http://djdjdjdjdjinvalidUrl.dkdkdk", function(data) {
console.log("in success function");
});
}
function crosser(data) {
console.log("in crosser");
}
$(document).ready(function(){
$.when(checker()).done(crosser);
});
See jsFiddle for a live example.
you need to return a promise from checker
function checker() {
console.log("in checker");
return $.getJSON("http://djdjdjdjdjinvalidUrl.dkdkdk", function(data) {
console.log("in success function");
});
}
Demo: Fiddle
Also there is no need to use $.when()
$(document).ready(function(){
checker().done(crosser);
});
Demo: Fiddle
For asynchronous events like $.getJSON, you need to use the actual deferred object. I've updated your jsfiddle with this object in use: http://jsfiddle.net/wM7aP/1/
Code:
function checker() {
var dfd = new jQuery.Deferred();
console.log("in checker");
$.getJSON("http://djdjdjdjdjinvalidUrl.dkdkdk", function(data) {
//handle data here
dfd.resolve( "hurray" );
});
return dfd.promise();
}
function crosser(data) {
console.log("in crosser");
}
$(document).ready(function(){
$.when(checker()).done(crosser);
});
I'm using pretty standard setup I think. A click on element to call a function that handles an ajax request.
My limited understanding of variable scope and callbacks when using asynchronous anything and trying to figure out jQuery deferreds is making my feeble brain hurt.
$('<div>')
.on({
click : function(){
console.log(
fetchMyData() // this will be 'undefined' but why?
)
}
})
function fetchMyData(){
$.ajax({
// ajax setup
})
.done(function(response){
console.log( response ); // shows 'hello' as expected
return response;
})
}
I get that the ajax call will not necessarily be done by the time I'm doing the console.log(), since it's asynchronous of course.
So how can I make it such that fetchMyData() will display the ajax result once it's ready?
You should change what fetchMyData function does. Try returning the promise object.
$('<div>').click(function()
{
var fetchMyDataPromise = fetchMyData() ;
fetchMyDataPromise.done(function(response)
{
console.log(response);
});
});
function fetchMyData()
{
return $.ajax({ // ajax setup });
}
You can use jQuery When like this :
$('<div>')
.on({
click : function() {
$.when(fetchMyData()).then(function(data) {
console.log(data);
});
}
});
function fetchMyData(){
return $.ajax({
// ajax setup
});
}
So how can I make it such that fetchMyData() will display the ajax result once it's ready?
You've already done that, in the .done callback. If you want fetchMyData to return the response, you have to use a synchronous call, which is usually not the right thing to do (because the UI will freeze until the response arrives).
Maybe you want to modify your function to take a callback:
function fetchMyData(thenDoThis){
$.ajax({
// ajax setup
}).done(thenDoThis)
}
function doSomethingWithResponse(response) {
// do something
}
Then call it like this:
fetchMyData(doSomethingWithResponse);
Or like this:
$('<div>').click(function() {
fetchMyData(function(response){
console.log(response);
});
});
I have one JS function that makes an ajax call and runs continuously
function First(ServerId)
{
var CallServer = jQuery.ajax({
type: "POST",
url: "somefile.php",
dataType: "json",
success: function(response)
{
// do something here
First(response.ServerId);
}
}};
}
In somefile.php there's a sleep timer of 60 seconds, so ajax call returns response after 60 seconds. Every time a different server id is returned.
Now I have another function and I want to do something like this
function Second()
{
/*
wait for 5 seconds to see if function First() has returned server id
if (ServerIdIsReturned)
{
i) abort CallServer
ii) make another Ajax call (CallServer2)
iii) after CallServer2 is done, call CallServer with the returned ServerId
}
else
{
i) abort CallServer
ii) make another Ajax call (CallServer2)
iii) after CallServer2 is done, call CallServer with the ServerId as 0
}
*/
}
I am not sure if I have explained it properly, but I want to check in function Second() if function First() has returned a new server id and accordingly proceed further. I think I'd need to use setTimeout and breakup the Second() function, but not sure.
How can I accomplish this?
Just call the second function in the success block of your first function.
success: function(response) {
// do something here
First(response.ServerId);
// proceed further
Second();
}
in order to make a delayed call just use setTimeout(Second,5000);
set a global variable to false before the call and set it to true when the call has returned then you can just check that variable
Why not just use the built in timeout ability of the jQuery ajax call - set your 5 second timeout and then add an error handler - check for a timeout and call again, if appropriate.
var CallServer = jQuery.ajax({
type: "POST",
url: "somefile.php",
timeout:5000,
dataType: "json",
success: function(response)
{
// do something here
First(response.ServerId);
},
complete(jqXHR, textStatus)
{
if (textStatus === "timeout")
{
Second();
}
}
}};