var ajaxStuff = (function () {
var doAjaxStuff = function() {
//an ajax call
}
return {
doAjaxStuff : doAjaxStuff
}
})();
Is there any way to make use of this pattern, and fetch the response from a successful ajaxcall when calling my method? Something like this:
ajaxStuff.doAjaxStuff(successHandler(data){
//data should contain the object fetched by ajax
});
Hope you get the idea, otherwise I'll elaborate.
Two things:
1. Add a parameter to the doAjaxStuff function.
2. When invoking doAjaxStuff, pass in an anonymous function (or the name of a function)
var ajaxSuff = (function () {
var doAjaxStuff = function(callback) {
// do ajax call, then:
callback(dataFromAjaxCall);
}
return {
doAjaxStuff : doAjaxStuff
}
})();
// calling it:
ajaxStuff.doAjaxStuff(function(data){
//data should contain the object fetched by ajax
});
Just let doAjaxStuff accept a callback:
var doAjaxStuff = function(callback) {
// an ajax call
// Inside the Ajax success handler, call
callback(response); // or whatever the variable name is
}
Depending on your overall goals, you could also use deferred objects instead (or in addition). This makes your code highly modular. For example:
var doAjaxStuff = function() {
// $.ajax is just an example, any Ajax related function returns a promise
// object. You can also create your own deferred object.
return $.ajax({...});
}
// calling:
ajaxStuff.doAjaxStuff().done(function(data) {
// ...
});
I believe you need to read the jQuery docs for jQuery.ajax. You could make a call as simple as:
$.ajax('/path/to/file').success(function (data) {
doStuff();
})
Related
I would like to make a function that returns a promise. That promise would contain the data of an asynchronous call made in the function. What I want it to look like :
//Function that do asynchronous work
function f1() {
var url = ...
WinJS.xhr({ url: url }).then(
function completed(request) {
var data = ...processing the request...
...
},
function error(request) {
...
});
}
//Code that would use the result of the asynchronous function
f1().done(function(data) {
...
});
The only way I found to make this work is to pass a callback to f1 and call it when I have the data. Using callbacks though seems to defeat the goal achieved by promises. Is there a way to make it work like above? Also, I could return WinJS.xhr in f1, but the done method of f1 would return the request and not the "data".
There's little to change:
function f1() {
var url = …;
return WinJS.xhr({ url: url }).then(function completed(request) {
// ^^^^^^
var data = …; // processing the request
return data;
// ^^^^^^^^^^^
});
}
//Code that would use the result of the asynchronous function
f1().done(function(data) {
…
}, function error(request) {
… // better handle errors in the end
});
You don't want to return the WinJS.xhr() itself indeed, but you want to return the result of the .then(…) call which is exactly the promise that resolves with the return value of the callback. This is one of the main features of promises :-)
So, I've built an api object that can be included in any JavaScript file via require.js. In the api object, I have calls to create Backbone models/collections like the one shown below:
getDatapoints: function(attributes, callback) {
require(['models/datapoint'], function(Datapoint){
var datapoint = new Datapoint.DatapointCollection(attributes);
datapoint.fetch({success: function(data){
return callback(data.toJSON());
}});
});
}
I want to have a way of being able to start multiple calls and run a callback function once ALL calls have completed. It looks like jQuery's $.when function does what I want, but I'm not sure how to get it to work with anything besides $.ajax calls.
Am I looking in the right place? Should I be looking at something like q.js?
Expanding on #mattacular's answer:
API = {
getDatapoints: function (attributes){
var dfd = $.Deferred();
require(['models/datapoint'], function(Datapoint){
var dataPoints = new Datapoint.DatapointCollection(attributes);
dataPoints.fetch().then(function (points){
dfd.resolve(points.toJSON());
}, function (error){
dfd.reject(error);
});
});
return dfd.promise();
},
getAllDatapoints: function (arrayOfAttributes){
var arrayOfPromises = arrayOfAttributes.map(this.getDatapoints);
return $.when.apply($, arrayOfPromises);
}
}
And where you're actually calling the getAllDatapoints method:
var allDatapointAttributes = [{...}, {...}, {...}];
API.getAllDatapoints(allDatapointAttributes).done(function(){
console.log.apply(console, arguments);
// should output an array of arrays containing dataPoint
// objects when all the requests have completed successfully.
});
You can do this using jQuery's Deferred object. Here is a quick example:
getDatapoints: function (attributes, callback() {
var dataPoints = $.Deferred();
// perform async calls here
// when "done," call dataPoints.resolve() or dataPoints.reject() accordingly
return dataPoints.promise();
}
edit: removed outdated tutorial
my first post here, hi everyone :)
i have this js code to access a json api:
function a() {
//does some things
//...
//then calls function b
b(some_params);
}
function b(params) {
//calls an objects method that makes an ajax call to an api and get the response in json
someObject.makeajaxcalltoapi(params, function(response) {
alertFunction(response);
});
}
function alertFunction(resp) {
console.log ("the response is: ");
console.log(resp);
}
this is working ok, but now i need to modify it in order to do this:
in function a(), instead of making a single call to b(), i need to call b() multiple times in a loop, with different parameters each time.
and then i want to call alertFunction() passing it an array with all the responses, but only after all responses have been received.
i have tried to use $.when and .then, after seeing some examples on deferred objects, but its not working:
function a() {
//does some things
//...
//then calls function b
var allResponses = [];
$.when(
anArray.forEach(function(element) {
allResponses.push(b(some_params));
});
).then(function() {
alertFunction(allResponses);
});
}
function b(params) {
//calls an objects method that makes an ajax call to an api and get the response in json
someObject.makeajaxcalltoapi(params, function(response) {
//alertFunction(response);
});
return response;
}
function alertFunction(allresp) {
console.log ("the responses are: ");
console.log(allresp);
}
any help?
UPDATE - ok finally got it working. i put here the final code in case it helps somebody else...
function a() {
//does some things
//...
//then calls function b
var requests = [];
//-- populate requests array
anArray.forEach(function(element) {
requests.push(b(some_params));
});
$.when.apply($, requests).then(function() {
alertFunction(arguments);
});
}
function b(params) {
var def = $.Deferred();
//calls an objects method that makes an ajax call to an api and get the response in json
someObject.makeajaxcalltoapi(params, function(response) {
def.resolve(response);
});
return def.promise();
}
function alertFunction(allresp) {
console.log ("the responses are: ");
console.log(allresp);
}
Here is one way to use $.when with an unknown number of AJAX calls:
$(function () {
var requests = [];
//-- for loop to generate requests
for (var i = 0; i < 5; i++) {
requests.push( $.getJSON('...') );
}
//-- apply array to $.when()
$.when.apply($, requests).then(function () {
//-- arguments will contain all results
console.log(arguments);
});
});
Edit
Applied to your code, it should look something like this:
function a() {
var requests = [];
//-- populate requests array
anArray.forEach(function(element) {
requests.push(b(some_params));
});
$.when.apply($, requests).then(function() {
alertFunction(arguments);
});
}
function b(params) {
//-- In order for this to work, you must call some asynchronous
//-- jQuery function without providing a callback
return someObject.makeajaxcalltoapi();
}
function alertFunction(allresp) {
console.log ("the responses are: ");
console.log(allresp);
}
I want to extend all of my application's ajax calls with some special case handlers and be able to refire the method that started the ajax call if I need to. The problem I am having is I cannot get the name of the calling function that triggered the ajax call from my anonymous function event handlers, either ajaxSend or ajaxSuccess. I have tried all of the variations of caller/callee that are commented below plus many others. Here is some sample code:
var ajaxcaller;
$(document).ajaxSend(function(event,xhr,settings){
// Before we fire off our call lets store the caller.
// ajaxcaller = arguments.callee.caller.name;
//alert("get caller:"+arguments.callee.caller.name);
//alert("get caller:"+caller.name);
//alert("get caller:"+this.caller.toString());
//alert("get caller:"+event.caller.toString());
});
$(document).ajaxSuccess(function(event,xhr,settings){
var xobj = $.parseJSON(request.responseText);
if(xobj.ReFire === 1){
//Successful ajax call but not results we expected, let's refire
//Fix some params automagically here then
//SOME CODE HERE THAT Refires my caller
}
});
$(document).ajaxError(function(event,xhr,settings){
var xobj = $.parseJSON(request.responseText);
if(xobj.ReFire === 1){
//Fix some params automagically here then
//SOME CODE HERE THAT Refires my caller
}
});
Here's an idea, however I am not sure how reliable it would be, but you could intercept jQuery.ajax calls and append a caller property to the options that would reference the calling function as well as an args property that would reference the arguments that were passed to that function.
I am sure that if you play around with that idea, you will find a solution to your problem. If you don't like the idea of overriding jQuery.ajax, you could simply make sure to pass those references as options in all your ajax calls.
DEMO: http://jsfiddle.net/zVsk2/
jQuery.ajax = (function (fn) {
return function (options) {
var caller = arguments.callee.caller;
options.caller = caller;
options.args = caller.arguments;
return fn.apply(this, arguments);
};
})(jQuery.ajax);
$(document).ajaxSend(function (e, xhr, options) {
console.log('caller', options.caller);
console.log('args', options.args);
});
function getRecords(someArgument) {
return $.ajax({
url: '/echo/json/',
dataType: 'json',
data: {
json: JSON.stringify({ test: someArgument})
}
});
}
getRecords(1);
getRecords(2);
I'm probably missing something simple but given this JS code:
var WS = {
whoami: function () {
var toReturn;
$.getJSON("/SecurityData/GetCurrentUser", function (data) {
toReturn = data.Email;
});
return toReturn;
}
}
When I call it, if I put a breakpoint on the toReturn = data.Email, the expected data is there but if don't WS.whoami is undefined.
I assume this is because the $.getJSON call is async, but how can I get the desired effect?
Ajax is asynchronous and returns a promise object. Instead, return the promise object and add a callback to it.
var WS = {
whoami: function () {
return $.getJSON("/SecurityData/GetCurrentUser");
}
};
WS.whoami().done(function(data){
alert(data.Email);
});
The only other option would be to make it a synchronous request, however I do not recommend it due to the impact it will have on your UX. You would have to use $.ajax and async:false
A better solution would be to call your function with a callback. This way, your code stays async, and continues when the json call is complete.
var WS = {
whoami: function (callback) {
$.getJSON("/SecurityData/GetCurrentUser", callback);
}
}
WS.whoami(function(data) {
// code that uses var data
});