I am using promise like this:
var restClient = {
serveRequest: function(rUrl, type, body, rHeaders, rAsync, callback) {
var promise = jQuery.ajax({
url: rUrl,
type: type,
data: body,
headers: rHeaders,
async: rAsync,
contentType: "text/plain",
dataType: "json"
});
promise.then(onSuccess, onError);
},
onSuccess: function(data) {
callback(data);
},
onError: function(msg) {
console.log(msg.responseText);
}
}
How can I pass arguments (callback) in promise.then onSuccess? I want to use that in onSuccess method later.
I am using promise like this
Well, first of all, you shouldn't. The purpose of promises is to be returned as results from asynchronous functions, so that you don't need callback parameters any more. You'd better just do
var restClient = {
serveRequest: function(rUrl, type, body, rHeaders, rAsync) {
var promise = jQuery.ajax({
url: rUrl,
type: type,
data: body,
headers: rHeaders,
async: rAsync,
contentType: "text/plain",
dataType: "json"
});
return promise;
}
};
and let the caller of restClient.serveRequest(…) invoke .then(…).
How can I pass arguments (callback) in promise.then onSuccess?
You don't need that onSuccess. Just directly use
promise.then(callback, function(msg) {
console.log(msg.responseText);
});
I want to use that in onSuccess method later.
You cannot. It tries to use callback, but that is a parameter local to the serveRequest method - so onSuccess could at most be a local function in there, but not a method on its own.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
function getData(url) {
var responseData = null;
$.ajax({
type: "GET",
url: url,
crossDomain: true,
async: false,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function (result) {
responseData = result;
}
});
console.log(responseData);
return responseData;
}
var getapidata= getData('https://jsonplaceholder.typicode.com/todos/1');
console.log('getapidata',getapidata);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
It's an async event, So you should do something similar this syntaxe may help:
function getData(url) {
return $.ajax({
type: "GET",
url: url,
crossDomain: true,
contentType: "application/json; charset=utf-8",
dataType: "jsonp"
});
}
var getapidata = getData('https://jsonplaceholder.typicode.com/todos/1').then(value => {
console.log(value)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I think you don't want to write $.ajax syntax every time when you need to send ajax call. if so then this code can help you.
Note You should must learn how JavaScript asynchronously works because the which you have written will never work.
Here is my code in which i have add some more functionality.
1) dynamically set URL and Methods
2) Now you can GET, POST, PUT, PATCH, DELETE using getData() function
getData() function required two parameter and one optional parameter depending upon you need to send data on server or not.
getData(URL, Method, Data if there)
$(document).ready(async () => {
function getData(url, method, data = {}) {
return $.ajax({
method,
url,
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
});
}
// getData(URL, Method, Data)
// await getData('https://jsonplaceholder.typicode.com/posts/1', 'PATCH', {title: "new post"})
// await getData('https://jsonplaceholder.typicode.com/posts/1', 'DELETE')
// await getData('https://jsonplaceholder.typicode.com/posts', 'POST', {
// userId: Math.floor(Math.random() * 1000),
// title: "New Post",
// body: "This is my new post"
// })
var getapidata = await getData('https://jsonplaceholder.typicode.com/posts/1', 'GET')
console.log(getapidata)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Thank you
I'm trying to implement a function that after consulting a service brings the variables as global.
function ajax_test(str1, callback){
$.ajax({
url: '/path/service',
type: 'POST',
dataType: "json",
data: {'vars':$('form').serialize(), 'test':123},
success: function(data, status, xhr){
callback(data);
}
});
}
and I'm trying to call like this:
ajax_test("str", function(url) {
//do something with url
console.log(url);
});
Now, if I just call ajax_test() it returns an error, saying that callback is not a function.
How would be the best way to simply call the function and get the results to use global variables?
Edit:
I think a good question is: what is a good alternative to async: false? How is the best way to implement synchronous callback?
Edit 2:
For now, I'm using $.post() with $.ajaxSetup({async: false}); and it works how I expect. Still looking a way I could use with a callback.
Have to set the scope inside the success method. Adding the following should work.
function ajax_test(str1, callback){
$.ajax({
url: '/path/service',
type: 'POST',
dataType: "json",
data: {'vars':$('form').serialize(), 'test':123},
success: function(data, status, xhr){
this.callback(data);
}.bind(this)
});
}
As an argument of the ajax_test function, callback is in the scope of the ajax_test function definition and can be called anywhere there, particularly in the successcase. Note that calling ajax_test() without arguments will as expected make your code call a function that does not exist, named callback.
The following sends an Ajax request to the jsFiddle echo service (both examples of callback as anonymous or global function are given in the jsFiddle), and works properly :
function ajax_test(str1, callback){
$.ajax({
url: '/echo/json',
type: 'POST',
dataType: "json",
data: {
json: JSON.stringify({
'vars':$('form').serialize(),
'test':123
})
},
success: function(data, status, xhr){
callback(data);
}
});
}
ajax_test("unusedString", function(data){
console.log("Callback (echo from jsFiddle called), data :", data);
});
Can you check that the webservice you're calling returns successfully ? Here is the jsFiddle, I hope you can adapt it to your need :
https://jsfiddle.net/dyjjv3o0
UPDATE: similar code using an object
function ajax_test(str1) {
this.JSONFromAjax = null;
var self = this;
function callback(data) {
console.log("Hello, data :", data);
console.log("Hello, this :", this);
$("#callbackResultId").append("<p>Anonymous function : " + JSON.stringify(data) + "</p>");
this.JSONFromAjax = JSON.stringify(data);
}
$.ajax({
url: '/echo/json',
type: 'POST',
dataType: "json",
data: {
json: JSON.stringify({
'vars': $('form').serialize(),
'test': 123
})
},
success: function(data, status, xhr) {
console.log("Success ajax");
// 'self' is the object, force callback to use 'self' as 'this' internally.
// We cannot use 'this' directly here as it refers to the 'ajax' object provided by jQuery
callback.call(self, data);
}
});
}
var obj = new ajax_test("unusedString");
// Right after the creation, Ajax request did not complete
console.log("obj.JSONFromAjax", obj.JSONFromAjax);
setTimeout(function(){
// Ajax request completed, obj has been updated
console.log("obj.JSONFromAjax", obj.JSONFromAjax);
}, 2000)
You cannot expect the Ajax request to complete immediately (don't know how it behaves with async: false though, this is why you need to wait for a while before getting the actual response.
Updated jsFiddle here : http://jsfiddle.net/jjt39mg3
Hope this helps!
I´m using $.when to determine, when an array of ajax promises are finished. I encountered, that the moment $.when fires the ajax calls are finished, but their callbacks / done functions aren´t. How can I wait for the callbacks to be finished?
the ajax calls look like this:
$.ajax({
method: 'POST',
url: url,
data: formData,
processData: false,
contentType: false
}).then(
function(data) {
data = JSON.parse(data);
var url = data.url;
obj.set('src', url);
});
and $.when s.th. like this:
$.when(promises).done(function(){
// the values of objs change in the .done function of the request above
// but when the following ajax got fired, the values haven´t changed yet
if(DEV) console.info('send Json: ', objs);
$.ajax({
method: "POST",
url: url,
data: objs
});
});
I would do this by using jQuery v1.8 or later and using then rather than fail and done and success/failure callbacks:
var promise1 = $.ajax({
/* ...params...*/
}).then(
function(data) {
// Handle success; if you modify what you get, `return` it
// and it will get propagated
return /*...`data` or updated `data` as appropriate...*/;
},
function(error) {
// Handle failure
}
);
var promise2 = /*...*/;
Then
$.when(promise1, promise2).then(
function(data) {
// Handle overall success; this will be called after the
// earlier `then` callbacks on each request
},
function(error) {
// Handle failure
}
);
Live example on jsFiddle (sadly, Stack Snippets don't provide any ajax features); full source below
Note that $.when expects discrete arguments, not an array. If you really have an array, then:
$.when.apply($, promises).then(
// ...
);
...or of course on a modern JavaScript engine:
Promise.all(promises).then(
// ...
);
Full source of the fiddle above, which uses jQuery v2.2.4:
log("Starting");
var promise1 = $.ajax({
url: "/echo/json/"
}).then(
function(data) {
// Handle success; if you modify what you get, `return` it
// and it will get propagated
log("Got promise1's response, returning 'p1'");
return 'p1';
},
function(error) {
// Handle failure
}
);
var promise2 = $.ajax({
url: "/echo/json/"
}).then(
function(data) {
// Handle success; if you modify what you get, `return` it
// and it will get propagated
log("Got promise2's response, returning 'p2'");
return 'p2';
},
function(error) {
// Handle failure
}
);
$.when(promise1, promise2).then(
function(result1, result2) {
// Handle overall success; this will be called after the
// earlier `then` callbacks on each request
log("Both are done", result1, result2);
},
function(error) {
// Handle failure
}
);
function log() {
// Old-fashioned to stay ES5 compatible
$("<pre>").text(Array.prototype.join.call(arguments, ", ")).appendTo(document.body);
}
Can you chain your promises? With something like this (not tested):
$.ajax({
method: 'POST',
url: url,
data: formData,
processData: false,
contentType: false
}).then(
function(data) {
data = JSON.parse(data);
var url = data.url;
obj.set('src', url);
// return your promises (if possible, I don't know where they come from)
return promises
}).then(
function() {
if(DEV)
console.info('send Json: ', objs);
$.ajax({
method: "POST",
url: url,
data: objs
});
});
use this
$.ajax({
method: 'POST',
url: url,
data: formData,
processData: false,
contentType: false,
success: function(data){/* to handle success response */},
error: function(error){/* to handle error response */},
complete: function(data){/* to handle the response success or error*/}
});
the data = JSON.parse(data); in your ajax function is not mutating the data object but create a new data object, you need to return it back so the caller can grab it
Try it like this,
function getData(){
return $.ajax({
method: 'POST',
url: url,
data: formData,
processData: false,
contentType: false
}).then(
function(data) {
data = JSON.parse(data);
var url = data.url;
obj.set('src', url);
return data;
});
}
var data = $.when(promises).done(getData);
My question is there is a way to define timeout for each parallel ajax post when we used jquery deffered interface. E.g.
parallelPost: function(toUrl1, toUrl2, theData1, theData2, contentType, dataType, successHandler, errorHandelr, completeHandler) {
$.when($.ajax(this.createAjaxCall(toUrl1, theData1, true, headers, 'POST', contentType, dataType,1000)),
$.ajax(this.createAjaxCall(toUrl2, theData2, true, headers, 'POST', contentType, dataType,2000))).done(function(res1, res2) {
successHandler(res1, res2);
}, errorHandelr, completeHandler);
},
createAjaxCall: function(toUrl, theData, isAsync, headers, verb, contentType, dataType, timeout, successHandler, errorHandelr, completeHandler) {
return {
url: toUrl,
cache: false,
type: verb,
data: theData,
dataType: dataType,
timeout: timeout || 0,
async: isAsync,
headers: headers,
contentType: contentType ? contentType : 'application/x-www-form-urlencoded',
success: successHandler,
error: errorHandelr,
complete: completeHandler
};
}
The timeouts for each parallel posts were defined 1000 and 2000. My goal to get those responses that were succeeded in defined timeouts. Thus, when the first request was time-outed and second was not, then return only second response.
Via jquery deffered interface if at least one is time-outed fail callback is called.
Is there is a way to define such behavior or may be another interface that provide solution to issue
Here's how I would do this ...
First, for the general principle, read this answer.
Now, implement reflect() in the guise of a chainable .jqXhrReflect() method, which returns:
on success: jQuery.ajax success args bundled into a single object,
on error: a promise resolved with jQuery.ajax error args bundled into a single object.
(function($) {
if(!$.$P) {
$.$P = function() {
return (this instanceof $.$P) ? this : (new $.$P());
};
}
if(!$.$P.prototype.jqXhrReflect) {
$.$P.prototype.jqXhrReflect = function() {
/* A promise method that "reflects" a jqXHR response.
* Delivers, on the success path, an object that bundles :
* - jqXHR success arguments (data, textStatus, xhr) or
* - jqXHR error arguments (xhr, textStatus, errorThrown).
*/
return this.then(
function(data, textStatus, xhr) { return { 'data':data, 'textStatus':textStatus, 'xhr':xhr }; },
function(xhr, textStatus, errorThrown) { return $.when({ 'xhr':xhr, 'textStatus':textStatus, 'errorThrown':errorThrown }); }
);
};
}
})(jQuery);
Note: Custom jQuery promise methods are not intuitive
Then change parallelPost() as follows :
to accept ready-formed ajax options,
not to accept successHandler, errorHandelr, completeHandler args,
to filter the ajax responses in order to separate out results and errors.
parallelPost: function(ajaxOptions1, ajaxOptions2) {
return $.when(
this.ajaxCall(ajaxOptions1),
this.ajaxCall(ajaxOptions2)
).then(function() {
var args = Array.prototype.slice.call(arguments);
// here, apply various filters
return {
all: args,
results: args.filter(function(obj) {
return obj.data !== undefined;
}),
allErrors: args.filter(function(obj) {
return obj.errorThrown !== undefined;
}),
timeouts: args.filter(function(obj) {
return obj.errorThrown && obj.textStatus === 'timeout';
}),
otherErrors: args.filter(function(obj) {
return obj.errorThrown && obj.textStatus !== 'timeout';
})
};
});
},
Then change .createAjaxCall() to actually perform the ajax call and transmogrify the response using the .jqXhrReflect() method defined above :
ajaxCall: function(ajaxOptions) {
var ajaxDefaults = {
cache: false,
type: 'POST',
dataType: 'JSON', // or whatever
async: false,
contentType: 'application/x-www-form-urlencoded'
};
return $.ajax($.extend(ajaxDefaults, ajaxOptions)) // $.extend does the necessary magic of merging ajaxDefaults and ajaxOptions.
.promise($.$P()) // make the .jqXhrReflect() method available.
.jqXhrReflect(); // call the .jqXhrReflect() method.
}
Now you can call,
myObj.parallelPost(
{ url: 'path/to/resource1', timeout: 1000 },
{ url: 'path/to/resource2', timeout: 2000 }
).then(function(outcomes) {
// this success callback is guaranteed to fire and will make the following available :
// array outcomes.all
// array outcomes.results
// array outcomes.allErrors
// array outcomes.timeouts
// array outcomes.otherErrors
});
I have an Ember promise call as below;
var promise = new Ember.RSVP.Promise(function(resolve, reject) {
return $.ajax({
//want this common
url: requestUrl,
type: type, // HTTP method
dataType: dataType, // type of data expected from the API response
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(postData)
})
.done(function(data, status, xhrObject) {
//But want this to be different
// resolve call
})
.fail(function(xhrObject, status, error){
// reject call
});
})
My question is can I use common code for $.ajax(), but have different implementation for done() callback
I can check that by passing some parameter from the calling place.
so basically, I want
if (someparam == 'handleDone1')
call resolve(data)
else
call resolve({data})
You are currently passing a function to done by hard coding a function expression into it.
Replace that with a variable. Pass a value to that variable as a function argument.
Alternatively, don't use done here at all. Just return the return value of $.ajax() and call done() on that in the calling function.
return a promise instead of ajax call. And wrap the ajax call into promise.
checkout the below code. It may helps.
function someFunction(resolve1, reject1) {
return new Ember.RSVP.Promise(function(resolve, reject) {
$.ajax({
//want this common
url: requestUrl,
type: type, // HTTP method
dataType: dataType, // type of data expected from the API response
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(postData)
})
.done(function(data, status, xhrObject) {
//But want this to be different
// resolve call
var dicision = resolve1();
if(dicision){
resolve(data);
} else {
resolve({data});
}
})
.fail(function(xhrObject, status, error){
// reject call
});
}