I want to return the second ajaxcall as result of the ajax function, can anyone help me.
private ajax(url: string, method:string, data:any = null) {
var _this = this;
return this.csrfWithoutDone().done(function (res) {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': res
}
});
return $.ajax({
url: _this.baseUrl + url,
type: method,
data: data,
});
});
}
the csrfWithoutDone function:
return $.ajax({
url: _this.baseUrl + '/api/csrf',
type: 'GET'
});
BTW: this is writen in typescript but if you replace private with function and remove the : (type) it works in js too.
What you should do is CHAIN the calls.
The .done() function is asynchronous. Therefore it will execute whatever you pass it as an argument when the response is back. That function's returned value goes nowhere.
What you should do instead is:
foo.then(function() { /*step 1 /}).then(function({ / step 2 */ })
I would suggest reading a little bit about asynchrounousity in Javascript.
This is the way you would do it with promises, I have never worked with jQuery so the syntax might differ.
edit: I would add that there is no way to return the response value in your initial function. the best you can do is return the jqXHR object, And then call the "then()" or "done()" from the caller.
You should return a Promised object in your ajax function, to be able to find out if your request is done or not. Since you are using jQuery, you can use Deferred Objects:
function ajax(url, method, data) {
var _this = this;
// Create a deferred object
var dfd = $.Deferred();
this.csrfWithoutDone().done(function (res) {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': res
}
});
$.ajax({
url: _this.baseUrl + url,
type: method,
data: data,
}).done(function (response) {
// your inner ajax has been done
// tell your promised object and pass the response to it
dfd.resolve(response);
});
});
// return promised
return dfd.promise();
}
// call your ajax function, it is a promised object
var ajaxRequest = ajax();
// so you can wait for the response
ajaxRequest.done(function (response) {
// your ajax has been done and you have the response
console.log(response);
});
I've implemented a simple code to find out how Promised object works:
function ajax() {
var dfd = $.Deferred();
setTimeout(function () {
dfd.resolve('Hello World');
}, 1000);
return dfd.promise();
}
var testResult = ajax();
testResult.done(function (response) {
alert(response);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can use native Promise Object as well, and maybe you need polyfill, to support all browsers, see Can I Use.
Related
Can someone shed a light on this, so I have multiple GET ajax calls and its only a few lines of codes but I'm basically repeating $.ajax({}) on every function.
Can I have 1 function of $.ajax({}) instead and use this on the functions so I don't need to repeat $.ajax({}) every time?
Something like this maybe but I'm sure its not right but its just a concept.
function ajaxCall(url, method) {
$.ajax({
url: url,
method: method,
success: function(){ } // however this should come in the below function
})
}
function firstCall() {
var url = 'www.urlsample.com';
var methodType = 'GET'
ajaxCall(url, methodType).success() // get the data from this function?
}
Is this somehow possible to do? its to avoid repeating ajax call for every function.
jQuery's .ajax() method returns a Promise-Wrapper.
function ajaxCall(url, method) {
// return promise
return $.ajax({
url: url,
method: method
});
}
function firstCall() {
var url = 'www.urlsample.com';
var methodType = 'GET'
ajaxCall(url, methodType).then(function( result ) {
// success handler
}, function( error ) {
// error handler
});
}
I want to update the page only when the function "removeDocx" be executed.
But in my case, timeout of the timer is perceived as the completion of "wait" function.
Where is the problem, and how can I solve it?
There is an example of code:
$(function () {
$.when(wait()).done(function () {
location.href = location.href;
});
});
function wait() {
var pm = { ISN_DOC: GetrcId(document.location.href) };
if (isNaN(pm.ISN_DOC))
setTimeout(wait, 500);
else removeDocx();
}
function removeDocx() {
var def = $.Deferred();
var url = "MinPrj/Collage.asmx/clearPattern?isn_doc=" + pm.ISN_DOC;
$.ajax({
type: 'POST',
url: rootpath + url,
contentType: 'application/json'
}).done(function (r) {
def.resolve();
}).fail(def.reject());
return def;
}
From the documentation:
jQuery.when( deferreds )
deferreds
Type: Deferred
Zero or more Deferred objects, or plain JavaScript objects.
You are passing a regular function, not a Deferred object so…
If a single argument is passed to jQuery.when() and it is not a Deferred or a Promise, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately.
First of all fix your removeDocx function. $.ajax already returns a deferred object:
function removeDocx() {
var url = "MinPrj/Collage.asmx/clearPattern?isn_doc=" + pm.ISN_DOC;
return $.ajax({
type: 'POST',
url: rootpath + url,
contentType: 'application/json'
});
}
Now wait function has to return a deferred as well (for it to work with $.when). The problem is that you have to share state between different (pseudo-recursive) calls to wait. Something like this might work:
function wait(def) {
if (!def) {
var def = $.Deferred();
}
var pm = { ISN_DOC: GetrcId(document.location.href) };
if (isNaN(pm.ISN_DOC)) {
setTimeout(function() {
wait(def);
}, 500);
} else {
$.when(removeDocx()).then(def.resolve);
}
return def;
}
The rest of the code stays as it was, i.e. you call wait() without args.
I am trying to write a JS code that will cancel the "btn_submit" buttons .onclick event if the given number already exists in the database. I use AJAX to query the DB for the given number and to determine if the should send the data to a .php site which will upload the question. To determine this I need the numOfRows variable's value, but because I set it in AJAX it will stay on 0. The validation() function will finish before my AJAX query finishes and this causes the problem that will always state that the given number does not exist in the DB (numOfRows will always stay on 0).
How can I await the AJAX query's finish before I compare the numOfRows to 0 in my validation() function's ending lines? If the number already exists in the DB, I need to return false to this line:
document.getElementById("btn_submit").onclick = validation;
Thank you!
var textAreaList;
var numOfRows = 0;
var finished = false;
document.getElementById("btn_submit").onclick = validation;
textAreaList = document.getElementsByClassName("text_input");
function validation() {
loadNumRows();
try {
document.getElementById('failure').hidden = true;
}
catch(e) {
console.log(e.message);
}
textAreaList = document.getElementsByClassName("text_input");
var failValidation = false;
for (var i = 0; i < textAreaList.length; i++) {
console.log(textAreaList[i]);
if (textAreaList[i].value == "") {
textAreaList[i].style.border = "2px solid #ff0000";
failValidation = true;
} else {
textAreaList[i].style.border = "2px solid #286C2B";
}
}
return !(failValidation || numOfRows != 0);
}
function loadNumRows(){
$.ajax({
url: 'php/SeeIfNumberExists?number=' + document.getElementById('number_inp').value,
type: "GET",
cache: false,
success: function (html) {
numOfRows = parseInt(html);
}
});
}
use of async/await with a transpilers like Babel to get it working in older browsers. You’ll also have to install this Babel preset and polyfill from npm:
npm i -D babel-preset-env babel-polyfill
Then
function getData(ajaxurl) {
return $.ajax({
url: ajaxurl,
type: 'GET',
});
};
async function test() {
try {
const res = await getData('https://api.icndb.com/jokes/random')
console.log(res)
} catch(err) {
console.log(err);
}
}
test();
or the .then callback is just another way to write the same logic.
getData(ajaxurl).then((res) => {
console.log(res)
});
Using async: false is an extremely bad idea, and defeats the whole purpose of using AJAX at the first place — AJAX is meant to be asynchronous. If you want to wait for a response from your script when you make the AJAX call, simply use deferred objects and promises:
var validation = function () {
var numberCheck = $.ajax({
url: 'php/SeeIfNumberExists?number=' + $('#number_inp').val(),
type: "GET"
});
// Listen to AJAX completion
numberCheck.done(function(html) {
var numOfRows = parseInt(html),
textAreaList = $('.text_input'),
finished = false;
// Rest of your code starts here
try {
document.getElementById('failure').hidden = true;
}
catch(e) {
console.log(e.message);
}
// ... and the rest
});
}
// Bind events using jQuery
$('#btn_submit').click(validation);
I see in your code that you are using a mixture of both native JS and jQuery — it helps if you stick to one :)
Never use async:false its dangerous, your app might misbehave.
You can use await only when your response returns a promise.
Unfortunately jQuery ajax doesn't return Promise when its completed.
But you can use promise in ajax request and return the promise when its done.
function asyncAjax(url){
return new Promise(function(resolve, reject) {
$.ajax({
url: url,
type: "GET",
dataType: "json",
beforeSend: function() {
},
success: function(data) {
resolve(data) // Resolve promise and when success
},
error: function(err) {
reject(err) // Reject the promise and go to catch()
}
});
});
}
We have converted ajax call into promise so now we can use await.
try{
const result = await asyncAjax('your url');
} catch(e){
console.log(e);
}
this works for me
async function doAjax() {
const result = await $.ajax({
url: "https://api.exchangerate-api.com/v4/latest/USD",
type: 'GET',
});
return result;
}
async function tt(){
var res = await doAjax()
var money = res.rates.INR
console.log(money)
}
tt()
(I acknowledge this is not the best way to go about things, but this is the quickest way to get your code working as is. Really though, you should rethink how you are pulling the numOfRows value so that it will work with truly asynchronous Ajax. All that being said...):
Start by setting async : false in the $.ajax call. The A in Ajax stands for asynchronous. That means, execution continues rather than waiting for it to return. You want to turn that off (i.e. make it synchronous). Actually, that should be the whole solution given the code you have there.
$.ajax({
url: 'php/SeeIfNumberExists?number=' + document.getElementById('number_inp').value,
type: "GET",
async: false,
cache: false,
success: function (html) {
numOfRows = parseInt(html);
}
});
One caveat from the docs for $.ajax:
Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active. As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done() or the deprecated jqXHR.success().
I'm writing a function that handles results from an Angular $http. In my $http request I'm using .then() to handle results.
var GET = function (url) {
return $http({
method: 'GET',
url: url
}).then(
function (data) {
return data.data;
},
function (data) {
return data.data;
});
};
And then I call the GET function from another function, like this:
var initializeUsers = function () {
return dbService.GET(serverUrl + dbResource).then(
function (data) {
// Some code to handle success
},
function (data) {
// Some code to handle error
});
};
Here's the problem: If there is an error in the HTTP request, it is being handled by the error handler in the GET function. BUT, when the initializeUsers is run, the error handler is NOT triggered, but rather the success handler. So the error does not "bubble" up, which is should
However, if I, instead of using .then in the GET function, I use .success and .error, like this:
var GET = function (url) {
return $http({
method: 'GET',
url: url
}).success(
function (data) {
return data.data;
}).error(
function (data) {
return data.data;
});
};
it works fine in the initializeUsers. HOWEVER, if I then call initializeUsers from another function using .then, the error handler in it is not triggered. I would seem that I have to use .success and .error all the way, which is not how it's supposed to work, as far as I can understand.
As long as I explicitly use .error on every function in order to actually catch the error, otherwise the error gets lost and the next function acts as though the last one was successful.
I'm I misunderstanding, or is there something wrong with my code?
If you return from a promise's error callback, it'll actually return a resolved (not rejected) promise. Use throw instead and the resulting promise will be rejected...
var GET = function (url) {
return $http({
method: 'GET',
url: url
}).then(
function (data) {
return data.data;
},
function (data) {
throw data.data; // use throw here
});
};
I am trying to wait for an ajax call to finish saving a model before saving the next model in the list. I was googling around and saw some stuff about deferred objects which are new to me, and another answer that had a recursive function do it. I tried the recursive method because it seemed to make a little more sense than with deferred objects and using $.when.apply($, arrayOfAjaxCalls).then(). So that code (the recursive one, looks like:
saveModel(index, numRequests) {
var self = this;
if (index < numRequests) {
var sample = self.samplesToSave[index];
return $.ajax({
url: model.url,
contentType: "application/json",
type: "POST",
data: JSON.stringify(model),
crossDomain: $.support.cors,
xhrFields: {
withCredentials: $.support.cors,
},
success: function(data) {
console.log("JUST SAVED");
console.log(data);
},
error: function(xhr: any) {
console.log(xhr);
},
}).then(() => {
self.saveModel(index + 1, numRequests);
});
}
}
I call this like:
saveModel(0, _.size(myCollection)
It doesn't actually wait for the ajax call to finish in its current state before calling the next saveModel. It basically just synchronously calls saveModel for each item in the collection in order. Any thoughts on what I'm missing? If there's a better solution with $.Deferred, I'm ok with that as well. Thanks.
Edit: Sorry it meant to say saveModel in the last line of the saveModel function. Was trying to get rid of parts that were domain specific. And I'm using typescript, not coffeescript
New attempt:
saveSampleNew() {
var d = $.Deferred();
d.resolve();
var p = d.promise();
var self = this;
self.samplesToSave.forEach(sample => p = p.then(() => self.makeSaveRequest(sample)));
return p;
}
makeSaveRequest(sample) {
var self = this;
return $.ajax({
url: "samples",
contentType: "application/json",
type: "POST",
data: JSON.stringify(sample),
crossDomain: $.support.cors,
xhrFields: {
withCredentials: $.support.cors,
},
success: function(data) {
console.log("SAVED12");
console.log(data);
},
});
}
Because this code depends on other async calls from completing, I call this new attempt like this:
this.saveContainers(project).then(() => {
}).done(() => {
self.saveSampleNew();
});
No, it should work this way. If you think it doesn't wait, please provide more information on how you call it and how experience that it does synchronously recurse.
There is one catch however with the recursive call:
.then(function() {
self.saveModel(index + 1, numRequests);
})
The promise that is returned by then, and subsequently by your saveModel method, does resolve directly with the first ajax call, it does not wait for the recursive chain. The other ajax calls are still happening (sequentially, as expected), but are not being tracked by the resulting promise.
To get that, and properly chain the promises so that it resolves with the result of the last ("innermost") promise, you will need to return the promise from the callback to then:
.then(function() {
return self.saveModel(index + 1, numRequests);
})
I'd probably use a for loop rather than a recursive call here, generally - I find those easier to read in this context.
saveModel() {
var d = $.Deferred(); d.resolve();
var p = d.promise(); // to start the chain
this.samplesToSave.forEach(sample => p = p.then(() => makeSaveRequest(sample));
return p;
}
makeSaveRequest(sample) {
return $.ajax({...}); // make request using `sample` as data
}