For example
function getResult(field) {
$.ajaxSetup ({cache: false, async: false});
$.get("api.php?field="+field, function(i) {
result = i;
});
return result;
};
The problem with this is that result becomes global. If I do var result = i; then the parent function (getResult) cannot see the variable result.
Is there a clever way to do this?
The code that I have posted works correctly. I have set my AJAX calls to be done synchronously.
function doIt(arr) {
var result = [];
$.each(arr, function (y_u_key_jQuery_y_u_no_fix_api, value) {
result.push(value);
});
return result;
}
Generally what you want to do is create a local variable in the outer function that the inner function manipulates through closure scope
Let's assume that your AJAX call is synchronous. You can try this:
function getResult(field) {
var result;
$.get("api.php?field="+field, function(i) {
result = i;
});
return result;
};
This way, the variable result is no more global.
$.get() is an asynchronous call. Trying to return something from it will not work like you think it will. If you want to do something with the result, you should do it in the success callback.
Here is the documentation on get.
You can't actually return a value from a asynchronous call, rather you have to depend upon the response will be be handled by a callback function to be called on response arrival.
function getResult(field, callback) {
$.get("api.php?field=" + field, callback);
};
USAGE
getResult("someFieldName", function(data) {
var result = data;
// do something with the response from server
});
Related
This question already has answers here:
Javascript callback - how to return the result?
(3 answers)
Closed 8 years ago.
This is a noob JS question that I can't quite verbalize well enough to successfully Google.
function getUser(username){
var toReturn = { };
Restangular.one('users', username).get().then(function(result){
toReturn = result;
});
return toReturn //doesn't work
}
Restangular.one(...).get() initializes a REST call to get user data from the server. .then(...) is a callback that runs after data is returned. However, this getUser() function, as written, always returns an empty object, because it returns before the callback is triggered. How might I go about writing this function so that it returns the retrieved object?
(p.s. I know that this question is academic with regard to angular, since it handles promise resolutions transparently. I'm new to JS in general, and this is a general JS question).
Since server call is asynchronous, you should provide callback.
You can use promise or callback
Using Callback
function getUser(username, callback){
Restangular.one('users', username).get().then(function(result){
callback(result);
});
}
call: getUser('username', function(result){ /*do stuff here */ });
Using Promise
function getUser(username){
var callback;
var promise = {then: function(cb){
callback = cb;
}
};
Restangular.one('users', username).get().then(function(result){
callback(result);
});
return promise;
}
call: getUser('username').then(function(result){ /*do stuff here */ });)
Just try with:
function getUser(username, callback){
Restangular.one('users', username).get().then(callback);
}
getUser('hsz', function(result){
console.log(result);
});
The rest call is probably an async call. If you have control over the API, you can make a synchronous request which will then wait for it to return. Something like this:
function getUser(username){
var toReturn = { };
return Restangular.one('users', username).get().then(function(result){
return result;
});
}
It depends on how then is handled too. I'm assuming here that then() will return the result as well.
However, the best way in this scneario is to use a callback:
function getUser(username, callback) {
Restangular.one('users', username).get().then(callback);
}
Yes, that won't work because the problem is with your function. Every AJAX call is executed asynchronously, thus like the result.
If you have made an AJAX call like that, it will have to ask the browser to load that request, process the response and then execute the (function(result) { }) that you put as the last argument with the result.
So, you must change your function to have a callback too, like:
function getUser(username, onResultHandler){
Restangular.one('users', username).get().then(onResultHandler);
}
Then you can use it like this:
getUser('Daniel', function(user) { updateSomethingWithMyUser(user); });
Did you get it?
The simplest way, is to not overwrite the object you just created, because objects are passed around by reference.
For example:
var a = function() {
var b = {};
setTimeout(function() { b.a = 'hi'; }, 100);
return b;
}
b = a();
console.log(b); // Object {}
setTimeout(function() { console.log(b) }, 100); // Object {a: "hi"}
Because we simply set a property of the object, we are setting a property on the SAME object that got returned. When you do something like:
toReturn = result;
like in your function, you aren't changing the thing toReturn referenced, you are changing what toReturn references to (it used to reference to {}, now it references whatever result it).
So, in your case:
function getUser(username){
var toReturn = { };
Restangular.one('users', username).get().then(function(result){
toReturn.result = result;
});
return toReturn;
}
As soon as you get the result, toReturn.result will have it.
How might I go about writing this function so that it returns the retrieved object?
You can't, and you shouldn't. Restangular makes the call async so that your application can carry on running while waiting for a response.
If you want to make it look synchronous, I suggest the following approach (here's where its different from other answers):
function getUser(username){
return Restangular.one('users', username).get();
}
/* Usage */
getUser('username')
.then(function(result) {
/* do something with result */
});
function hello() {
var arr = [];
$.get(url, function (data) {
var items = $(data).find("item");
$(items).each(function (idx, item) {
arr.push(item);
});
});
return arr; //undefined because nested loops are not finished processing.
}
How do I make sure that arr is populated before returning it?
There is no way to escape from asynchronous calls. You would need callbacks to get the result of the GET call.
function asynCall() {
var response;
// Ajax call will update response here later.
return response;
}
var responseFromFun = asyncCall(); // This will be undefined or null.
This is how your code works now. So response will always be undefined or null.
To get the response from Ajax calls pass a callback to the function when invoking it instead of assigning a response to it.
function asyncCall(callBack) {
var response;
$.get(...) {
response = someValueReturnedFromServer;
callBack(response);
}
// There wont be a return here
}
asyncCall(function(response){
// Do something with response now
});
The downside here is that if you are passing arr object (in your code) to some other function even that has to be changed to use callbacks !
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
});
Here is my piece of code am trying:
initData:function(period)
{
this.getLoadObject('0',url, this.callbackFunction);
},
I want to receive a return value from callBackFunction, which I want to be returned by initData.
Can any body help me, am not so proficient with JS.
I tried similar question but didn't get help.
Actually, the callback function may very well be called asynchronously, that is after the return from the call to initData.
If it is synchronous however, you can do this:
initData:function(period)
{
var that = this;
var result;
this.getLoadObject('0',url, function() {
result = that.callbackFunction(arguments));
});
return result;
},
Although it's impossible to tell from your code snippet, it looks like your callback function will be called asynchronously. if this is the case you will need to set variables that you want to be populated by initData within the callback function itself.
you could also wrap the callback function:
var context = this;
this.getLoadObject('0',url, function() {
var returnedval = context.callbackFunction.apply(context,arguments);
context.SomeFuctionToUseValue(returnedval);
});
I think you could use variable outside the function, so you can access it inside the callback function and outside.
var result = false;
initData:function(period)
{
this.getLoadObject('0',url, this.callbackFunction);
//inside the callback you can modify the "result" then
return result;
},
When the form is submitted, I'm calling a function getPosts and passing through a variable str. What I'd like to do is get the data returned from that function.
// when the form is submitted
$('form#getSome').submit(function(){
var str = $("form#getSome").serialize();
var something = getPosts(str);
* This is where I'd like to get the data returned from getPosts()
return false;
});
// get the data
function getPosts(str){
$.getJSON('http://myurl.com/json?'+str+'&callback=?',
function(data) {
arrPosts = new Array();
$.each(data.posts, function(i,posts){
// build array here
});
return arrPosts;
});
};
I've tried many things, but have only gotten 'undefined' returned. I've tried console.log(something);, console.log(getPosts).
I'm missing something very fundamental here. Any help would be greatly appreciated.
EDIT:
What I'm trying to do is create a single function that would get posts. Then different events would call that function. I could then use that data. So one event may be submitting a form, another may be clicking a link, another lazy/endless scrolling. All could use the same getPosts function.
There's a lot of parsing out the results which amounts to a lot of lines of code. Was just trying to find a way to reuse that function. Do you think that would be possible?
$('a.thisLink').click(function(){
getPosts();
get the return from getPosts() and do something with it
});
$('form.thisForm').submit(function(){
getPosts();
get the return from getPosts() and do something with it
});
function getPosts(){
get the posts and return an array
}
Ajax requests are executed asynchronously, the callback function (function (data)) of getJSON is executed when the request ends, and returning a value in that callback has no effect, because is a nested function inside getPosts and its return value is never used.
Actually in your example, getPosts doesn't return anything and it ends its execution before the data is returned.
I would recommend you to work on your submit event handler, if you want to keep the getPosts function, you can introduce a callback parameter:
$('form#getSome').submit(function(){
var str = $("form#getSome").serialize();
getPosts(str, function (data) {
var array = [];
$.each(data.posts, function(i,posts){
// build array here
array.push(/* value to add */);
});
// array ready to work with...
//...
});
return false;
});
function getPosts(str, callback){
$.getJSON('http://myurl.com/json?'+str+'&callback=?', callback);
}
Edit 2: In response to your second comment, you could make another callback, that will be executed when the data has been processed by the first callback, and you can define it when you execute the getPosts function on the submit event handler:
$('form#getSome').submit(function(){
var str = $("form#getSome").serialize();
getPosts(str, reusableCallback, function (result) {
// result contains the returned value of 'reusableCallback' <---
});
return false;
});
function reusableCallback(data) {
var array = [];
$.each(data.posts, function(i,posts){
array.push(/* value to add */);
});
//...
return array;
}
function getPosts(str, callback, finishCallback){
$.getJSON('http://myurl.com/json?'+str+'&callback=?', function (data) {
finishCallback(callback(data)); // pass the returned value
// of callback, to 'finishCallback' which is
// anonymously defined on the submit handler
});
}
Edit 3: I think that the getPosts function and the "reusableCallback" function are strongly related, you might want to join them, and make the code easier to use and understand:
$('form#getSome').submit(function(){
var str = $("form#getSome").serialize();
getPosts(str, function (result) {
// result contains the processed results
});
return false;
});
function getPosts(str, finishCallback){
$.getJSON('http://myurl.com/json?'+str+'&callback=?', function (data) {
// process the results here
var array = [];
$.each(data.posts, function(i,posts){
array.push(/* value to add */);
});
//...
finishCallback(array); // when the array is ready, execute the callback
});
}
Your getPosts function looks incomplete, I'm no jquery expert but should it look something like:
function getPosts(str) {
$.getJSON('http://myexample.com/json?'+str+'&callback=?',function(data){
var arrPosts = [];
$.each(data.posts, function(i,posts){
... build array yada yada ...
});
return arrPosts;
});
}
The problem is that the $.getJSON callback function gets called when the get request returns the data, not inline with your function.