This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
I am working in javascript. I have two functions that both compute a value. Each function also makes an ajax call to a service and grabs some data. Normally, the data is just returned in an object. Both of these functions I want to occur on a button click, so I've wrapped both of my "Compute Functions" in another function. The compute functions set values. Those values that are set, how do I use them in my wrapper function? This may be something simple that I'm just not getting
function ComputeSum() {
$.ajax({
type: 'GET',
dataType: 'json',
url: constructedURL,
success:
function(data) {
callback(data);
stopSpinner();
var TheSum = 4+4;
return TheSum;
},
error: function (xhr, status, error) {
alert("Error - Something went wrong on the retrieval of already existing Hydraulic Data.");
//alert("Unable to communicate with server.Status is: " + status + "The error is: " + error + "The xhr is: " + xhr);
stopSpinner();
}
});
}
function ComputeDIf() {$.ajax({
type: 'GET',
dataType: 'json',
url: constructedURL,
success:
function(data) {
callback(data);
stopSpinner();
var TheDif = 10-2;
return TheDif;
},
error: function (xhr, status, error) {
alert("Error - Something went wrong on the retrieval of already existing Hydraulic Data.");
//alert("Unable to communicate with server.Status is: " + status + "The error is: " + error + "The xhr is: " + xhr);
stopSpinner();
}
});
}
So I have my two extra basic functions. I call these functions in another function thats attached to a button click
function Calculations() {
ComputeSum();
ComputeDif();
alert("The sum is: " + TheSum);
alert("The difference is: " + TheDif);
}
So my ajax call is returning an object but I also want to be able to use those values I created in the Compute Functions inside my wrapper function. Is this possible? What am I missing. Thanks in advance for your help.
Perhaps I'm not understanding the question, but why not use the return values like this:
function Calculations() {
var TheSum, TheDif;
TheSum = ComputeSum();
TheDif = ComputeDif();
alert("The sum is: " + TheSum);
alert("The difference is: " + TheDif);
}
The variables TheSum and TheDif are local variable and limited to the scope of each function. The use of var assures this.
You just assign the return values from the function to a local variable and then you can refer to that local variable within your function:
function Calculations() {
var sum = ComputeSum();
var dif = ComputeDif();
alert("The sum is: " + sum);
alert("The difference is: " + dif);
}
Related
I'm using p5.js to do some drawing using data from json fed by my Django backend. I have a my draw function defined at the base level of my html doc in the script element like so:
function draw(json) {
if (json["leaf_text"]) {
stroke(100)
ellipse(json["leaf_center_x"], json["leaf_center_y"], json["leaf_height"], json["leaf_width"]).rotate(json["leaf_rotate"]);
}
if (json["twig_text"]) {
stroke(100);
console.log("drawing twig....");
line(json["twig_base_x"], json["twig_base_y"], json["twig_tip_x"], json["twig_tip_y"]);
}
if (json["branch_text"]) {
stroke(150);
line(json["branch_base_x"], json["branch_base_y"], json["branch_tip_x"], json["branch_tip_y"]);
console.log("x1 " + json["branch_base_x"]);
console.log("x2 " + json["branch_base_y"]);
console.log("y1 " + json["branch_tip_x"]);
console.log("y2 " + json["branch_tip_y"]);
}
if (json["trunk_text"]) {
stroke(255);
line(json["trunk_base_x"], json["trunk_base_y"], json["trunk_tip_x"], json["trunk_tip_y"]);
}
}
This function is called upon receipt of a successful ajax response as follows. My problem is, I get a error in the js console because of the draw function.
TypeError: json is undefined
My understanding is that (please correct me where I am wrong) the 'draw' function is agnostic concerning whether or not 'json' exists or not and will wait and see what sort of object it is passed before it begins complaining that the parameter is not defined. Is this not the idea of a function in javascript?? I must be missing something. If this is the case, why would it complain that json is not defined?
if (json["leaf_text"]) {
$("#grow").click(
function(e) {
console.log("attempting ajax...");
e.preventDefault();
var csrftoken = getCookie('csrftoken');
var open_parens = ($("#txt").val()).indexOf("(");
var close_parens = ($("#txt").val()).indexOf(")");
var child = $("#txt").val().slice(0, open_parens);
var parent = $("#txt").val().slice(open_parens + 1, close_parens);
$.ajax({
url: window.location.href,
type: "POST",
data: {
csrfmiddlewaretoken: csrftoken,
child: child,
parent: parent,
mode: "grow"
},
success: function(json) {
setup();
draw(json);
...
}
},
error: function(xhr, errmsg, err) {
console.log(xhr.status + ": " + xhr.responseText);
}
});
});
If you use import called json, you should use different name as parameter for draw function (for example: draw(json_bar) or, in import, re-name json (for example: import json as json_foo).
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I usually do most of whats needed in the actual .done() function of any async type calls. But in this case I want to return the string as I need it multiple places but this function returns undefined all the time. The variable is out of scope of the async call so should be available to return no?
var stringIWantBack = function getTableEditorFieldArray(pageName, tableId) {
var searchString = 'webpagename[name ="' + pageName + '"] > tableid[id ="' + tableId + '"] > editor';
var fieldArray;
$.when(datatableUtility.GetInitStringXml())
.done(function (returnedXml) {
fieldArray = $(returnedXml).find(searchString).text();
return fieldArray;
})
.fail(function (jqXhr, textStatus, errorThrown) {
// alert("Error downloading projection data: " + textStatus + " Error: " + errorThrown);
toastr.warning('Error downloading datatable editor fields array: ' + textStatus + ' Error: ' + errorThrown);
});
}
You cannot return anything from an AJAX (asynchronous) function. It runs in the background, and the callbacks are called at some point in the future when it's done. By that point your function already returned and is finished.
What you can do is this:
function getTableEditorFieldArray(pageName, tableId) {
var searchString = 'webpagename[name ="' + pageName + '"] > tableid[id ="' + tableId + '"] > editor';
return $.when(datatableUtility.GetInitStringXml()).then(function (returnedXml) {
return $(returnedXml).find(searchString).text();
}).fail(function (jqXhr, textStatus, errorThrown) {
// alert("Error downloading projection data: " + textStatus + " Error: " + errorThrown);
toastr.warning('Error downloading datatable editor fields array: ' + textStatus + ' Error: ' + errorThrown);
});
}
Using .then() here instead of .done() will allow you to manipulate the data. The return there, will be sent to any .done() methods that you attach later.
For example:
getTableEditorFieldArray('test', 123).done(function(stringIWantBack){
// This will be the value returned from `.then()`
console.log(stringIWantBack);
});
The problem isn't one of scope. You are quite right that you can return fieldArray from your getTableEditorFieldArray() function.
var fieldArray;
$.when(/* ... */ );
return fieldArray;
At this point though, fieldArray's value is undefined. The $.when() code might as well not even be there, since it will wait for the next tick (outside of this call stack) to do any work.
You must accept a callback to return the value asynchronously. Note that you can return the promise returned by $.when(), and multiple bits of code can call .done() on it. Those callbacks set up with .done() will be called in the order in which they were defined.
I am creating an API and I want to show a code example in javascript that you can use to invoke the API.
I write a test function in javascript. I would like to be able to execute AND display the code for the javascript function(s) but I would rather only have one copy of the code to make maintenance easier.
Example, I have the following code:
function doauth_test(apikey,username,userpass)
{
$.ajax({
url: "/api/v1.2/user.php/doauth/" + username + "/" + userpass + "?apikey=" + apikey,
type: "GET",
success: function(data,textStatus,xhr) {
var obj = JSON.parse(data);
var authkey = obj.authkey; //store this somewhere for subsequent use
var user_id = obj.user_id; //store this somewhere for subsequent use
},
error: function(xhr, ajaxOptions, thrownError) {
alert("ERROR! Status code: " + xhr.status + " Response Text: " + xhr.responseText);
}
});
}
I want this code to be something I can EXECUTE and I want it to display the code in a DIV in my documentation example. But I do not want to (ideally) have two copies of this code.
You can call toString() on a function to get its source code.
Alternatively, you can use the DOM to get the text of the <script> tag.
Just use toString method for your function and it will return your function definition as a string.
alert(doauth_test.toString());
Hope it helps!
using this as a guide: http://msdn.microsoft.com/en-us/library/dd250846.aspx
can someone help me with the jquery call?
Do I actually pass in the javascript code for the callback, or just the name of the function?
BingSearch = function($bingUrl, $bingAppID, $keyword, $callBack) {
$bingUrl = $bingUrl + "?JsonType=callback&JsonCallback=" + $callBack + "&Appid=" + $bingAppID + "&query=" + encodeURI($keyword) + "&sources=web";
$.ajax({
dataType: 'jsonp',
jsonp: $callBack,
url: $bingUrl,
success: function(data) {
alert('success');
$callBack(data);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("error: " + textStatus);
}
});
};
Update
Ok so I changed this to:
BingSearch = function(bingUrl, bingAppID, keyword, callback) {
var url = bingUrl + "?method=?&JsonType=callback&Appid=" + bingAppID + "&query=" + encodeURI(keyword) + "&sources=web";
$.getJSON(url, callback);
};
Calling it like:
BingSearch(url, appid, searchkeyword, function(searchresults) {
alert('yes!');
};
Still getting the 'invalid label' error.
To use do jsonp with jQuery, replace the JsonCallback=UserCallback with JsonCallback=?. jQuery will then handle it like a regular $.ajax() request.
I suggest starting out with $.getJSON() to get used to the Bing API and moving back to $.ajax() when your ready to integrate it with your application.
Using the example from the Bing API docs:
var apikey = 'YOUR_API_KEY';
var url = 'http://api.bing.net/json.aspx?AppId='+apikey+'&Version=2.2&Market=en-US&Query=testign&Sources=web+spell&Web.Count=1&JsonType=callback&JsonCallback=?';
$.getJSON(url, function(data) { console.log(data); });
jsonp: needs to be set to a string (I think it can also be left out), as this is just the name of the dynamically created function used to receive the JSONP.
But the formal parameter $callBack needs to be a reference to a function, so either you use
function callback(result){ /*processResultHere*/ }
BingSearch(..,..,.., callback);
or
BingSearch..,..,.., function(result){ /*processResultHere*/ });
And just so you know it, the excessive use of $ really hurts my eyes :)
Also, function names beginning with a capital should be reserved for 'classes', as many syntax checkers will complain on functions with capitals being called without new in front..
I got stuck in this problem for an hour. I am thinking this is something relates to variable scoping ? Anyway, here is the code :
function loadRoutes(from_city)
{
$.ajax(
{
url: './ajax/loadRoutes.php',
async : true,
cache : false,
timeout : 10000,
type : "POST",
dataType: 'json',
data :
{
"from_city" : from_city
},
error : function(data)
{
console.log('error occured when trying to load routes');
},
success : function(data)
{
console.log('routes loaded successfully.');
$('#upperright').html(""); //reset upperright box to display nothing.
return data; //this line ruins all
//this section works just fine.
$.each(data.feedback, function(i, route)
{
console.log("route no. :" + i + " to_city : " + route.to_city + " price :" + route.price);
doSomethingHere(i);
});
}
});
}
The for each section works just fine inside the success callback region. I can see Firebug console outputs the route ids with no problem at all.
For decoupling purpose, I reckon it would be better to just return the data object, which in JSON format, to a variable in the caller function, like this:
//ajax load function
function findFromCity(continent, x, y)
{
console.log("clicked on " + continent + ' ' + x + ',' + y);
$.ajax(
{
url: './ajax/findFromCity.php',
async : true,
cache : false,
timeout : 10000,
type : "POST",
dataType : 'json',
data :
{
"continent" : continent,
"x" : x,
"y" : y
},
error : function(data)
{
console.log('error occured when trying to find the from city');
},
success : function(data)
{
var cityname = data.from_city;
//only query database if cityname was found
if(cityname != 'undefined' && cityname != 'nowhere')
{
console.log('from city found : ' + cityname);
data = loadRoutes(cityname);
console.log(data);
}
}
});
}
Then all of a sudden, everything stops working! Firebug console reports data object as "undefined"... hasn't that being assigned by the returning object from the method loadRoutes(cityname)?
Sorry my overall knowledge on javascript is quite limited, so now I am just like a "copycat" to work on my code in an amateur way.
Edited : Having seen Nick's hint, let me work on it now and see how it goes.
Edited 2nd :
bear with me, still stuck in this:
//ajax load function
function findFromCity(continent, x, y)
{
console.log("clicked on " + continent + ' ' + x + ',' + y);
var cityname = "nowhere"; //variable initialized.
$.ajax(
{
url: './ajax/findFromCity.php',
async : true,
cache : false,
timeout : 10000,
type : "POST",
dataType : 'json',
data :
{
"continent" : continent,
"x" : x,
"y" : y
},
error : function(data)
{
console.log('error occured when trying to find the from city');
},
success : function(data)
{
cityname = data.from_city;
//only query database if cityname was found
if(cityname != 'undefined' && cityname != 'nowhere')
{
console.log('from city found : ' + cityname);
//data = loadRoutes(cityname);
//console.log(data);
}
}
});
return cityname; //return after ajax call finished.
}
Firebug console prints out something interesting :
nowhere
from city found : Sydney
I thought the order should be at least reversed like this :
from city found : Sydney
nowhere
So, basically, the variable defined in success region has a completely different scope from the same variable outside? This sounds bizarre to me at first but now I see it.
Still, don't know how to pass the json object out of the success callback to assign it to another variable...
Conclusion : okay, I got it, working on "pass by reference" to make use of side-effect to change a variable passed in by function parameter now... Which is not directly related to this question.
The success callback occurs when the ajax call completes, so nothing is actually returned by your function, because that statement doesn't run until later.
In the AJAX scenario, you need to get the data object, then call what should run next, because any success or complete callback functions will happen after the code you're running, when the response from the server comes back.
You could maybe try this method:
function loadRoutes(parameters)
{
return $.ajax({
type: "GET",
async: false, // This is important... please see ref below
// Other Settings (don't forget the trailing comma after last setting)
success: function () {
console.log('Success');
},
error: function () {
console.log('Error');
}
}).responseText;
}
So basically, '.responseText' is added to the '$.ajax' request and the request itself then becomes the return value.
Please note: This usage - returning the result of the call into a variable - requires a synchronous (blocking) request. So use 'async:false' in the settings.
To return a JSON value you could use:
return $.parseJSON($.ajax({
// Other settings here...
}).responseText);
For more info see: http://api.jquery.com/jQuery.ajax.
Might be a "data" scope problem.
In the second example, which data is which the json object returned, and which one is the one sent?
Directly returning from the ajax success or error element will show the undefined value if you are doing some assigment like :
response = loadRoutes(XXX);
console.log(response); // undefined
Instead you have to follow approach of assigning first and returning later. so above code will look something like :
function loadRoutes(from_city)
{
var responsedata;
$.ajax(
{
url: './ajax/loadRoutes.php',
async : true,
cache : false,
timeout : 10000,
type : "POST",
dataType: 'json',
data :
{
"from_city" : from_city
},
error : function(data)
{
console.log('error occured when trying to load routes');
},
success : function(data)
{
console.log('routes loaded successfully.');
$('#upperright').html(""); //reset upperright box to display nothing.
//return data; //this line ruins all, change this to below line
responsedata=data // asssigning first
//this section works just fine.
$.each(data.feedback, function(i, route)
{
console.log("route no. :" + i + " to_city : " + route.to_city + " price :" + route.price);
doSomethingHere(i);
});
}
});
return responsedata; //returning later
}