AJAX request with forked callback - javascript

I have the problem that I want different callback routes for the same AJAX request because sometime it's necessary to use the same function (i.e. getting information about product ID or something similar).
What works is something like this:
function1() {
$.ajax({
url: "test.html",
context: document.body
}).done(function() {
route1function();
});
}
function2() {
$.ajax({
url: "test.html", // do the same crap here...
context: document.body
}).done(function() {
route2function();
});
}
function3() {
$.ajax({
url: "test.html", // and here again *yawn*
context: document.body
}).done(function() {
route3function();
});
}
Copy & Paste coding is evil, so my idea was to do something like:
doMyAmazingStuff(iRoute) {
$.ajax({
url: "test.html",
context: document.body
}).done(function() {
switch(iRoute) {
case 1:
route1function(data);
break;
case 2:
route2function(data);
break;
// and so on...
}
});
}
Unfortunately, iRoute will NOT be passed to the .done function and is undefined. Any alternatives how to survive such variables? Copy / paste / paste / paste ... like in the first example is no option (and bad style as well). And making them global scoped (setting a shadow variable without declaring it with var) isn't a that good solution, I think.

First, your statement "iRoute will NOT be passed to the .done function and is undefined" is incorrect. If you pass in iRoute to your function it will not be undefined. See this demonstration. I'm passing in 1 as an argument to the function and the alert within the done function is alerting that number.
There might be a tidier way of writing that code, but it's pretty much the same code - it just means using the AJAX promise interface to return the data from a separate function instead.
function getData() {
return $.ajax({
url: "test.html",
context: document.body
});
}
function doMyAmazingStuff(iRoute) {
getData.done(function (data) {
switch(iRoute) {
case 1:
route1function(data);
break;
case 2:
route2function(data);
break;
}
});
}
doMyAmazingStuff(1);

Related

calling nested javascript function in django template

I am new to both Django and Javascript and am having trouble calling a user defined function from within a javascript function in Django template.
I have a javascript block as follows:
function EditDialog(pk) {
$.ajax({
url: "{% url 'populatereviewform' %}",
method: 'GET',
data: {
pk: pk
},
success: function(formHtml){
//Do something
alert("Success!")
},
dataType: 'html'
});
// this is my function that I would like to call
function MyFunc(e, offset) {
alert("Calling my function")
}
// Now I try to call this function from another function
("#dialog").submit(function(e)
{
this.MyFunc(e, "1");
return false;
});
}
My question is how can I call this nested function?
In the code above, I am creating a function called MyFunc which I am trying to call from the submit method. However, this comes back with this.MyFunc is not a function.
The this is bound to something else.
Remove this and call your function like this: MyFunc().

jquery execute function when two conditions are met

I need to execute a specific function mvFinishItUp() when two conditions are met. More specifically, one condition is the callback success of a $.ajax the other is a normal flow of the code until it reaches the function. Kinda of this:
$.ajax({
url: mv_finalUrl,
success: function (data) {
mvFinishItUp(data);
},
dataType: 'html'
});
/* here a lot more code, with animations and some delays */
mvFinishItUp(data) {
/* My function code */
/* But this code must only run after it has been called via the call back
and after all the other code has been ran as well */
}
So, the function must wait for all the code if the ajax callback is quicker, or the other way around. Any ideas on how this could be implemented?
I'm willing to change the whole concept of script code, as I believe the loose code between the ajax, and the function itself should go to a function aswell ...
This is a perfect use case for jQuery Deferred objects.
Remove the success: parameter from the AJAX call, and register the handler later:
var jqxhr = $.ajax(...);
// do some other synchronous stuff
...
// and *then* register the callback
jqxhr.done(mvFinishItUp);
Deferred objects cope perfectly well (by design) with being registered on an AJAX event after that event already finished.
Try like below, (It is just psuedo code)
var isAJAXDone = false, isFunctionCodeDone = false;
$.ajax({
//..
success: function () {
isAJAXDone = true;
mvFinishItUp(data, isAJAXDone, isFunctionCodeDone);
}
});
//..Your function code
//..Add this below the last line before the function ends
isFunctionCodeDone = true;
mvFinishItUp(data, isAJAXDone, isFunctionCodeDone);
//..
mvFinishItUp(data, isAJAXDone, isFunctionCodeDone ) {
if (isAJAXDone && isFunctionCodeDone) {
//Do your magic
}
}
Maybe something like this would do the trick:
var _data = undefined;
$.ajax({
url: mv_finalUrl,
success: function (data) {
_data = data;
myFinishItUp(data); // call the function from here if it's faster
},
dataType: 'html'
});
/* here a lot more code, with animations and some delays */
function myFinishItUp(data) {
this.data = data; // store the data from the AJAX call or the code, whichever reaches first
// if the code reaches this before the AJAX call completes, data will be undefined
if(typeof this.wasCalled == "undefined") {
/* My function code */
/* But this code must only run after it has been called via the call back
and after all the other code has been ran as well */
this.wasCalled = true;
}
}(_data); // function that calls itself when the code gets to this point with a self-contained boolean variable to keep track of whether it has already been called
I used a self calling function execute when the code flow gets to that point, but if it's called from the AJAX call, it won't execute. It keeps track of whether or not it's already been called with a self-contained boolean value.
Here I add an second parameter to check callback check
function mvFinishItUp(data, byCallback) {
var iscallback = byCallback || false; // if you don't send byCallback
// default will false
if(iscallback) {
// execute if called by callback
}
}
success: function (data) {
mvFinishItUp(data, true); // call with second parameter true
},
To execute mvFinishItUp() after ajax done and all codes between ajax and mvFinishItUp finished you can do something like this:
var allFunctionExecuted = false; // global to detect all code execution
$.ajax({
url: mv_finalUrl,
success: function (data) {
mvFinishItUp(data, true);
},
dataType: 'html'
});
function func1() {
}
function func2() {
}
// some other code
function func3() {
allFunctionExecuted = true;
}
Now,
function mvFinishItUp(data, byCallback) {
var iscallback = byCallback || false; // if you don't send byCallback
// default will false
if(iscallback && allFunctionExecuted) {
// execute if ajax done
// and others code done
}
}
This is very "ugly" code, but you can modify it to not use global vars, so this is just illustrative:
var ajaxExecuted = false,
codeExecuted = false;
$.ajax({
url: mv_finalUrl,
success: function (data) {
ajaxExecuted = true;
mvFinishItUp(data);
},
dataType: 'html'
});
/* here a lot more code, with animations and some delays */
codeExecuted = true;
mvFinishItUp(data) {
/* My function code */
if(ajaxExecuted && codeExecuted) {
/* But this code must only run after it has been called via the call back
and after all the other code has been ran as well */
}
}
I just added two flags: ajaxExecuted and codeExecuted, and inside the function an if statement that checks the value of the those flags, and executes only when the two of them are set to true. So no mather who calls it first, it get only executed when the two flags are set to true.
A cleaner way could be to implement the function in an object, and use properties instead of global vars.

How do I get the data out of a JavaScript function

I have this:
var myapp;
function Menu($scope){
$.ajax({
url: "/user.php",
type: "POST",
success: function(data){
}
});
}
How do I use the data out of the function scope?
You're having trouble because the ajax operation is asynchronous. This means that, after $.ajax is called, you can't control when exactly the response will arrive. In the mean time, your code keeps running normally, and if you try to use the response before it arrives, it will be empty.
You say in the comments that a framework calls your Menu function, so I'm assuming you can't control what parameters are passed to it. In this case, you should only use the data inside the success callback:
function Menu($scope){
$.ajax({
url: "/user.php",
type: "POST",
success: function(data){
// USE data HERE
}
});
}
In case you can modify how Menu is called, you can pass a callback function to it, and let that manipulate the results:
function Menu($scope, ajaxCallback){
$.ajax({
url: "/user.php",
type: "POST",
success: ajaxCallback
});
}
// Define the callback where you will use the data
function processData(data) {
// USE data HERE
}
// Call Menu passing the callback
Menu(whateverScopeIs, processData);
You can create a variable at the scope you need, and save the data to that variable. Or you can call a function and pass that data to it.
For example:
function alertData(data){
alert(data); // I can use the data here now!
}
var foo;
$.ajax({
url: "/user.php",
type: "POST",
success: function(data){
alertData(data);
}
});
}
Create a global variable, assign data to it, and then use the global variable.
e.g.
var foo;
function bar(baz) {
foo = baz;
}
bar("test");
alert(foo);

jQuery Ajax How do callbacks work?

Hello fellow programmers! I just started an additional programming project and swore to god my code will bo SO much cleaner and easily upgradeable than it has been before.
Then I stumbled upon my "arch enemy" the jQuery AJAX returning. Last time I wanted to return something from an AJAX call I had to bend over and just make the call synchronous. That made things sticky and ugly and I hope that this time I will find something better.
So I have been googling/searching stackoverflow for a while now, and just don't understand this solution many ppl has gotten which is called callback function. Could someone give me an example on how I could exploit these callback functions in order to return my login statuses:
function doLogin(username, password) {
$.ajax({
url: 'jose.php?do=login&user='+username+'&pass='+password,
dataType: 'json',
success: function(data) {
if(data.success==1) {
return('1');
} else {
return('2');
}
$('#spinner').hide();
},
statusCode: {
403:function() {
LogStatus('Slavefile error: Forbidden. Aborting.');
$('#spinner').hide();
return (3);
},
404:function() {
LogStatus('Slavefile was not found. Aborting.');
$('#spinner').hide();
return (3);
},
500:function() {
LogStatus('Slavefile error: Internal server error. Aborting.');
$('#spinner').hide();
return (3);
},
501:function() {
LogStatus('Slavefile error: Not implemented. Aborting.');
$('#spinner').hide();
return (3);
}
},
async: true
});
}
So as you probably know, you cannot use return the way I have done from inside an AJAX call. You should instead use callback functions which I have no idea of how to use.
I'd be VERY greatful if someone could write me this code using callback functions and explaining to me just HOW they WORK.
EDIT:
I REALLY need to return stuff, not use it right away. This function is being called from within another function and should be able to be called from different places without being rewritten even slightly.
/EDIT
Sincerly,
Akke
Web Developer at Oy Aimo Latvala Ab
There are three parts to the basic "I need an asynchronous callback" pattern:
Give the function a callback function parameter.
Call the callback function instead of returning a value.
Instead of calling the function and doing something with its return value, the return value will be passed to your callback function as a parameter.
Suppose your synchronous mind wants to do this:
function doLogin(username, password) {
// ...
return something;
}
switch(doLogin(u, p)) {
case '1':
//...
break;
case '2':
//...
break;
//...
}
but doLogin has to make an asynchronous call to a remote server. You'd just need to rearrange things a little bit like this:
function doLogin(username, password, callback) {
return $.ajax({
// ...
success: function(data) {
if(data.success == 1)
callback('1');
else
callback('2');
},
//...
});
}
var jqxhr = doLogin(u, p, function(statusCode) {
switch(statusCode)) {
case '1':
//...
break;
case '2':
//...
break;
//...
}
});
The jqxhr allows you to reference the AJAX connection before it returns, you'd use it if you needed to cancel the call, attach extra handlers, etc.
A callback is simply a function that runs when certain conditions are met. In this case, it is when ajax has a "success".
You are already using a callback, but you don't recognize it. success: function(data) {} is a callback, but it's just what's called an anonymous function. It has no name or reference, but it still runs. If you want to change this anonymous function to a named function, it is really simple: take the code in the anonymous function, and put it in a named one, and then just call the named one:
[...]success: function(data) {
if(data.success==1) {
return('1');
} else {
return('2');
}
$('#spinner').hide();
}, [...]
should change to:
[...]success: function(){ callbackThingy(data) }, [...]
And now just create the callbackThingy function:
function callbackThingy(data){
if(data.success==1) {
someOtherFunction('1');
} else {
someOtherFunction('2');
}
$('#spinner').hide();
}
Note that the "return" value does nothing. It just stops the callback function, whether you are in an anonymous function or a named one. So you would also have to write a second function called someOtherFunction:
function someOtherFunction(inValue){
if(inValue=='1') {
// do something.
} else if(inValue=='2') {
// do something else.
}
}
The above example is if you have to pass parameters. If you do not need to pass parameters, the setup is simpler:
[...]success: callbackThingy, [...]
function callbackThingy(){
// do something here.
}
From the edit in your original post, I can see that you just need to store a (more) global variable. Try this:
// in the global scope , create this variable:
// (or -- at least -- in the scope available to both this ajax call
// and where you are going to use it)
var valHolder = -1;
// then edit your ajax call like this:
[...]
success: function(data) {
if(data.success==1) {
valHolder = 1;
} else {
valHolder = 2;
}
$('#spinner').hide();
},
[...]
Now you can verify 3 things:
valHolder = -1 means that the ajax call has not yet returned successfully
valHolder = 1 means data.success = 1
valHolder = 2 means data.success != 1.
Another option is to store the variable in an HTML attribute of some element.
Finally, you should probably look at jquery.data for the most jquery way of managing stored data.
Does this help?
Just as a small point of interest, you don't have to include
async : true;
as part of your $.ajax options. The default setting for async is already "true".
Sorry to post this as a response, but until I have 50 rep I can't make a simple comment. (Feel free to help me out with that! ^_^ )

Still Having Problems Returning Value Through Function

I'm having serious problems with the function below:
function requestUploadedSearch()
{
var cookie = JSON.parse(readCookie("user_search_cookie"));
$.ajax({
dataType: "script",
async: false,
data: {
context: "search-get",
code: removeNull(cookie, cookie !== null, "code")
},
success: function(data)
{
var keywords = search_return["keywords"];
return keywords; // here is the damn problem.
}
});
}
Seams that simply nothing comes out of the function except for the undefined value and no errors are shown in the debugger.
And I'm seriously almost throwing my laptop on the wall.
If anyone could help me doing this, please answer!
Thanks in advance.
1st off: Where is the search_return variable? Why are you ignoring data?
I have a feeling this is what you want to do:
function requestUploadedSearch()
{
var cookie = JSON.parse(readCookie("user_search_cookie"));
var keywords;
$.ajax({
dataType: "json",
async: false,
data: {
context: "search-get",
code: removeNull(cookie, cookie !== null, "code")
},
success: function(data)
{
keywords = data["keywords"];
}
});
return keywords;
}
The issue is that since the Ajax call will complete at an arbitrary time in the future, you cannot simply return a value from its success handler.
One issue is that you're not actually doing anything with the data returned by the server, which seems puzzling.
The nutshell version is that you need to implement the functionality as part of the success callback. That can be done in-line, or you can create the callback function outside of the Ajax call itself and use it as the value for the success property:
function onSuccess(data) {
// Do something with the data here
}
...
$.ajax({ // etc.
success: onSuccess
};
You may also use jQuery's $.when function.
The problem is the scope you're trying to return your keywords from. The success function is called by jQuery, and you don't have any control over what jQuery does with that return value. You could do return $.ajax(... but you wouldn't get what you expect, since according to the documentation: "As of jQuery 1.5, the $.ajax() method returns the jqXHR object, which is a superset of the XMLHTTPRequest object" (http://api.jquery.com/Types/#jqXHR).
What you should do instead is set up a callback function like:
function doSomethingWithKeywords(keywords) {
// do stuff
};
and in the success function call that function:
doSomethingWithKeywords(keywords);
EDIT: Hogan's is a good solution, since your call isn't asynchronous.
The problem you are having is the return you are passing is not the return of the function -- it is the return of the event of success. Often closures (implied passing of a local variable to a function) are used to solve this problem in JavaScript.
NB I still don't think your function will work because I don't see where search_return["keywords"] is defined. But at least you won't have to worry about the closure issue. Once your success function is correct the main function will return it.
Like this:
function requestUploadedSearch()
{
var cookie = JSON.parse(readCookie("user_search_cookie"));
var returnClosure;
$.ajax({
dataType: "script",
async: false,
data: {
context: "search-get",
code: removeNull(cookie, cookie !== null, "code")
},
success: function(data)
{
// returnClosure = data["keywords"];
returnClosure = search_return["keywords"];
}
});
return returnClosure;
}

Categories

Resources