This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Why are Callbacks from Promise `.then` Methods an Anti-Pattern
(2 answers)
Closed 5 years ago.
Currently I have 2 functions which call some of my API endpoints. They're setup to take a request followed by a success & failure callback functions. I'm trying to call my DeleteTask function from the success callback of my DeleteTaskUser function. However the DeleteTaskUser function is never firing.
I am pretty new to javascript, trying to build this application as a way to learn it so I could be misunderstanding how to use callbacks in javascript.
Any ideas?
The 2 functions:
this.DeleteTaskUser = function(request, success, failure){
AuthService.resHttp({
method: 'DELETE',
resource: 'DeleteAssignments',
params : request
}).then(
function(res) {
success(res)
},
function(res) {
failure(res)
}
);
}
this.DeleteTask = function(request, success, failure){
AuthService.resHttp({
method: 'DELETE',
resource: 'Task',
data : request
}).then(
function(res) {
success(res)
},
function(res) {
failure(res)
}
);
}
I am trying to call the functions as follows:
for(i = 0; i < $scope.tasksList.length; i++){
TaskApi.DeleteTaskUser(
{
id: $scope.tasksList[i].id,
},
//handle success
function(res){
//This function is never firing, despite the above function succeeding.
console.log("After Task User Deletion");
TaskApi.DeleteTask(
{
id: $scope.tasksList[i].id,
},
function(res){},
function(res){}
)
},
//handle failure
function(res){
console.log(res);
}
)
}
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
I have the code below:
remove Dog: function(dog) {
self = this;
const updated = this.pets.filter(o => o !== dog);
$.ajax({
type: "PATCH",
url: //irrelevant,
'data': //irrelevant,
'dataType': 'json',
success: function (result) {
self = this;
this.$emit('update:pets', updated);
},
error: function (result) {
}
});
}
I am trying to have an emit command after the success of the ajax request. The ajax works fine so don't worry about that. I am just unable to do the emitting because it says that this.$emit is not a function.
Can anyone help?
this property has access to your scope level properties because it's a function and not an arrow function. So when you access the properties or method which is not in the scope of that function, it returns undefined or not a function.
To fix it, Make your success function as an arrow function of Javascript.
success: (result) => {
this.$emit('update:pets', updated);
},
Another way is to remove the self inside the success method and use the outer self.
success: function (result) {
self.$emit('update:pets', updated);
},
I have a single-page app that uses a queuing mechanism based on promise, something like this:
a) a function that handles ajax requests
function AjaxSender(SomeAjaxData, FunctionToCallBack, SomeCallBackData) {
return $.ajax({
url: ...,
type: "POST",
data: SomeAjaxData,
success: function (msg, textStatus, request) {
if (FunctionToCallBack) {
FunctionToCallBack(SomeCallBackData);
//problem if there's a bug when this executes
}
}
});
}
b) a function that uses a promise object to queue requests
var AppAjaxPromise;
function AjaxRequestQueue(SomeAjaxData, FunctionToCallBack, SomeCallBackData) {
if (AppAjaxPromise) {
AppAjaxPromise = AppAjaxPromise.then(function () {
return AjaxSender(SomeAjaxData, FunctionToCallBack, SomeCallBackData);
});
return AppAjaxPromise;
}
AppAjaxPromise = AjaxSender(SomeAjaxData, FunctionToCallBack, SomeCallBackData);
return AppAjaxPromise;
}
When I want to send an ajax request, I call AjaxRequestQueue(TheAjaxData, TheFunctionToCallBack, TheCallBackData) and the queuing mechanism ensures that if multiple requests are sent simultaneously, or before one has finished returning, they are queued and processed one after the previous one is done.
The problem occurs when a bug stops the execution of the callback function. If that function bugs, the whole queuing mechanism stops and calling AjaxRequestQueue doesn't trigger ajax requests any more.
What do I need to do to fix this?
As jQuery's $.ajax returns a promise (and since you are using it), abandon the use of the success callback. Instead move that code in a then callback. This will allow you to chain a catch method (jQuery 3.x) call to it to respond to errors. If you don't trigger another error in that catch callback, the promise it returns will be resolved again (not rejected), so the rest of your chain will not be aborted:
function ajaxSender(someAjaxData, functionToCallBack, someCallBackData) {
return $.ajax({
url: ...,
type: "POST",
data: someAjaxData
}).then(function (msg, textStatus, request) {
if (functionToCallBack) {
functionToCallBack(someCallBackData);
}
}).catch(function (err) {
console.log('error occurred, but request queue will not be interrupted', err);
});
}
jQuery 2.x
The above needs jQuery 3.x. In jQuery versions before 3.x, you can replace the catch method like this (notice the null argument):
...
}).then(null, function (err) {
...
...but jQuery 2.x promises are not Promise/A+ compliant, which makes it a pain to get it right. Here is how you could do it for jQuery 2.x. This snippet uses a URL that mimics a delay and an HTTP response status code, which allows it to test request errors, JavaScript run time errors, and sequencing:
function ajaxSender(someAjaxData, functionToCallBack, someCallBackData) {
return $.ajax({
// URL for demo: server will use the sleep parameter in the data,
// and will return the given HTTP status
url: "http://httpstat.us/" + someAjaxData.status,
type: "GET", // The demo URL needs a GET
data: someAjaxData
}).then(function (data) {
if (functionToCallBack) {
try { // Would not be necessary if jQuery 2.x were Promise/A+ compliant
functionToCallBack(someCallBackData);
} catch (e) {
console.log(someCallBackData, 'Error occurred during callback');
}
}
}, function (err) { // This second function captures ajax errors
console.log(someCallBackData, 'HTTP error');
// Return a resolved promise.
// This would not be necessary if jQuery 2.x were Promise/A+ compliant
return $.when();
}); // In jQuery 3.x you would chain a catch call here instead of the try/catch.
}
var appAjaxPromise = $.when();
function ajaxRequestQueue(someAjaxData, functionToCallBack, someCallBackData) {
appAjaxPromise = appAjaxPromise.then(function () {
return ajaxSender(someAjaxData, functionToCallBack, someCallBackData);
});
return appAjaxPromise;
}
// Demo: the ajax data argument is also used to define the HTTP response status and
// the sleep time, and the data argument identifies the number of the call
// Survive an HTTP error
ajaxRequestQueue({ status: 404, sleep: 1000 }, myCallBack, 1);
// Survive a runtime error in the callback
ajaxRequestQueue({ status: 200, sleep: 2000 }, myErrorGeneratingCallBack, 2);
// Demo that the callback calls remain in the right order
ajaxRequestQueue({ status: 200, sleep: 3000 }, myCallBack, 3);
ajaxRequestQueue({ status: 200, sleep: 2000 }, myCallBack, 4);
ajaxRequestQueue({ status: 200, sleep: 1000 }, myCallBack, 5);
function myCallBack(data) {
console.log(data, "My callback is called");
}
function myErrorGeneratingCallBack(data) {
console.log(data, "My callback is called");
throw "I threw an error in my callback";
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can still continue the above pattern when moving to jQuery 3: it will still work. But ideally, you should then migrate the code to the catch-based version that I provided at the top.
Some other remarks
There is a consensus to only capitalise the first letter of a variable when it is a constructor/class.
By initialising appAjaxPromise as an immediately resolved promise, you can avoid code repetition:
var appAjaxPromise = $.when();
function ajaxRequestQueue(someAjaxData, functionToCallBack, someCallBackData) {
appAjaxPromise = appAjaxPromise.then(function () {
return ajaxSender(someAjaxData, functionToCallBack, someCallBackData);
});
return appAjaxPromise;
}
I am not sure if this answer will fix it, but the callbacks you are using in the success function might not be accessible from there.
You can add extra data to the request like so... and it will be accessible with 'this....'. (see success).
Not sure if you should ether :p I have been doing this to pass data from inside an object without having to change the ajax' context or using $.proxy. Also I have been able to access an object's function that fires a request, from inside that request's success, making it recursive for sending files in chunks.
If there are any comments on doing this, I would love to hear.
return $.ajax({
FunctionToCallBack: FunctionToCallBack,
SomeCallBackData: SomeCallBackData,
url: ...,
type: "POST",
data: SomeAjaxData,
success: function (msg, textStatus, request) {
if (this.FunctionToCallBack) {
this.FunctionToCallBack(this.SomeCallBackData);
//problem if there's a bug when this executes
}
}
});
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I recover data from a Requette in ajax. I want to use this data in a function and return it but when I call the function it returns nothing
function getdata(nom_produit) {
$.ajax({
type: "POST",
url: "traitement/panne/test_panne.php",
data: {
nom_produit: nom_produit
},
success: function(data) {
var obj = jQuery.parseJSON(data);
jQuery.each(obj["resultat"], function(index, value) {
})
}
});
return obj;
}
how i can return the data?
you can't return from like this. $.ajax is an asynchronous call so when return is called your success function is still pending execution. you can do something like below though to achieve same result.
function getdata(nom_produit, callback) {
$.ajax({
type: "POST",
url: "traitement/panne/test_panne.php",
data: {
nom_produit: nom_produit
},
success: callback
});
}
and from the place you are calling this function you can do something like below
var successFunction = function(data) {
hideOverlay(); // hide overlay once response is there
// your code to process data and show in UI
}
showOverlay(); // code to show loading image in UI till response comes
getData(someId, successFunction);
I'm attempting to write a couple of functions using jQuery to help me test some api endpoints that I'm writing in php. I'm a novice when it comes to Javascript and jQuery and I'm having difficulty working out what I need to read up on in order to get things working that way I need it.
Here are the requirements I'm attempting to meet:
Call should be non blocking
Functions only to be fired on success and in order
I need to pass parameters along with the functions rather than just function names
Each function needs to be able to access the data variable return by success: function(data) from within the api() function
I've read the jQuery docs and believe that deferred and promises are possibly the avenue I should be pursuing but I am not able to get an example working.
Simplified versions of my two functions:
(For clarity)
// Returns data from an api request providing something hasn't gone horribly wrong
function api( api, method, endpoint, query ) {
$.ajax({
type: method,
url: '/api/' + api + '/' + endpoint,
data: query,
dataType: 'json',
success: function(data) {
// I currently have a single hardcoded function
populate( data.result, '#resource', null );
},
error: function( data ) {
// Debug
dump(data.result);
}
});
// Do some other stuff here
}
// Example call
$('body').on('click', '#bigFatButton', function() {
// I would like to specify a function (or chain of functions)
// to be fired on success along with the api() function
api('resources', 'get', 'document', {
debug: '1',
id: '7'
})
});
This is what I'd like to achieve (something nice, short and reusable):
fn1() and fn2() are fired in order and can both access the data returned by api()
api('resources', 'get', 'document', {
debug: '1',
id: '7'
}).fn1(data, 'custom', 'params').fn2(data, {other: 'params'}).alert('wooty!');
What would be the best way of achieving something similar to this? A nudge in the right direction would be very much appreciated!
Thank you.
Try adding return statement before $.ajax() , returning data from api , utilizing .then()
function api( api, method, endpoint, query ) {
// return `$.ajax()` jQuery promise to `.then()`
return $.ajax({
type: method,
url: '/api/' + api + '/' + endpoint,
data: query,
dataType: 'json',
success: function(data) {
// I currently have a single hardcoded function
populate( data.result, '#resource', null );
// return `data`
return data
},
error: function( data ) {
// Debug
dump(data.result);
}
});
// Do some other stuff here
}
// Example call
$('body').on('click', '#bigFatButton', function() {
// I would like to specify a function (or chain of functions)
// to be fired on success along with the api() function
api('resources', 'get', 'document', {
debug: '1',
id: '7'
}).then(function(data) {
$.when(fn1(data, 'custom', 'params')
, fn2(data, {other: 'params'})
.then(function() {alert('wooty!')})
})
});
Due to the asynchronous nature of AJAX you can't chain functions directly from the API function. The data would simply not be available when the chained functions are ran. However you can do it inside the success function. You will need to construct a wrapper function.
function wrapper()
{
return {
fn1 : function(data){
//execute code for fn1 here
return wrapper();
},
fn2 : function(data){
//execute code for fn2 here
return wrapper();
},
alert : window.alert.bind(window);
}
}
}
By running wrapper.fn1(data, arguments).fn2(data, arguments).alert("whoot!") inside the success function it will work the way you intended.
Everytime you call upon the wrapper function, or a function inside it it will return the full object allowing for function chaining.
A more efficient design would be to construct the functions outside the wrapper object and only reference them inside the wrapper function.
1 - I would use the methods as arguments in an anonymous function
api('resources', 'get', 'document', {
debug : true, // better to say true or false :)
id : 7, // if your id is a number use number
callback : function(data){
fn1(data);
fn2(data);
}
});
2 - Using an array, could be cool if you have a lot to run.
// in api method..
for(var i; i < cbks.lengths; i++){
cbks[i](); // execute one by one the callbacks declared.
}
api('resources', 'get', 'document', {
debug : true, // better to say true or false :)
id : 7, // if your id is a number use number
[fn1, fn2, fn3] // here are the callbacks
});
I don't understand promises/deferred very much... I have something like that :
function callAjax() {
return $.ajax({
type: 'post',
dataType: 'jsonp',
data: {status: status, name: name},
url: '/test',
xhrFields: {
withCredentials: true
}
});
}
function connectAjax() {
var msg = 'doesnt work';
var promise = callAjax();
promise.then(function(data, textStatus, xhr) {
msg = 'it worked !';
}, function(data, textStatus, xhr) {
msg = 'it failed !';
});
console.log(msg); // output 'doesnt work'
}
I have tried a lot of different things (always, done, etc..) but couldn't make it work.
I use jsonp but my request isn't cross domain. I expect a 500 error from the server for my request.
For your example to work, you have to put the 'console.log(...)' statment INSIDE the two callback functions you register on the promise with .then(.., ..).
You have to keep in mind that the promise callback functions get called, only when the ajax call is finished.
Your script however does not wait until this happens and 'console.log(msg);' is executed before the ajax call returns.
This is a great example for the non-blocking nature of JavaScript.
For more detailed understanding look up resources on the JS event loop:
https://thomashunter.name/blog/the-javascript-event-loop-presentation/
Understanding the Event Loop