I'm trying to make a variable depend on the callback from an AJAX get function, however; I can't seem to get it working. I want to make sure that defaults.context always has a value before proceeding any other code.
What am I doing wrong or how can I achieve this in a proper way?
var defaults = {
currentCase: undefined,
context: {}
}
// Set defaults
function initDefaults(){
defaults.currentCase = getCurrentCase();
defaults.context = getContext(defaults.currentCase, function(object){
console.log(object); // logs the right data
return object;
});
console.log(defaults.context); // logs undefined
}
initDefaults();
// Get the ID of the current case
function getCurrentCase(){
return global_vars.project_ID;
}
function getContext(id, callback){
var obj = {};
$.get(global_vars.template_url + "/includes/load-project-context.php?id=" + id, function(data) {
obj = JSON.parse(data);
}).complete(function() {
callback(obj);
});
}
Thanks in regards,
Enzio
You can use something like
global_vars.template_url + "/includes/load-project-context.php?id=" + id, function(data) {
obj = JSON.parse(data);
}).complete(function() {
callback(obj);
}).fail(function() {
callback(error);
});
This is callback chaining. You can use other callbacks to handle other use cases.
Please check How to know when all ajax calls are complete
You will find there all what you need with quite good explanation
May be you should continue the further code in ajax callback.
// Set defaults
function initDefaults() {
defaults.currentCase = getCurrentCase();
getContext(defaults.currentCase, function(object) {
defaults.context = object; // Continue your code inside here
console.log(defaults.context); // Logs the right data
return object;
});
// This will still return `undefined` because this line will be executed
// before the ajax request finishes.
console.log(defaults.context);
}
Related
I Use odoo 10 and want to change pivot_view.js
I'm really confused with this code. I can't change the value.
Can you explain me about the right code ?
This is my code :
var value = false;
new Model('lhp.master').call('getValues', ['date', 'idx']).then(
function (result) { value = result[0]; }
);
console.log('value =',value);
Thank you for your help.
I think the problem is with how javascript promises work!
The order of the execution of the code is a s follows:
var value = flase;
calling the server method getValue by sending an http request;
console.log('value =',value); // which will print "value =fasle" on the console
after the http request earlier in step 2 is finished and a response is retrieved from the server. The callback function will be called with the result:
function (result) { value = result[0]; }
So, make sure to write the console.log part inside the callback method, like this:
function (result) {
value = result[0];
console.log('value =', value);
}
Is there a way to store data to a variable?
I tried:
$scope.another =
function(){
var new_data;
userService.getInfo().success(function(data){
new_data = data;
});
return new_data;
};
var data = $scope.another();
but it returns 'undefined' in the console log. Thank you
EDIT
I now get an empty array for new_data .
var new_data = [];
$scope.another =
function(callback){
userService.getInfo().success(function(data){
paymentService.getCashierParams({ "cardNumber": data.cardNumber}).success(function(data){
gameService.getAllgames({ "PID":data.GetCashierParameters.PID, "limit": 6, "skinID": 1}).success(function(data) {
callback(data.data.GetFlashGamesResult.Data.FlashGame);
});
});
});
};
$scope.another(function(result){
new_data = result;
});
console.log(new_data);
You need to think about this problem differently. Your getInfo method returns a promise. A promise's success callback is never immediately called. It may be called sometime in the future, but in the meantime your code will continue executing and the return value of $scope.another will be undefined.
Instead, place whatever logic you wish to execute within the success callback.
userService.getInfo().success(function (data) {
// Do stuff with data.
});
If you are not used to working with asynchronous data, this may seem weird. But it is much better than the alternative, which is hanging the page for potentially many seconds while a network request, database read, etc, completes.
If you are worried about indentation, you can create separate function(s) to handle the data.
function processData(data) {
// Process stuff...
return data;
}
function handleData(data) {
data = processData(data);
console.log(data);
}
userService.getInfo().success(handleData);
This is due to the asynchronous function that you called. Try to use callback instead. Something like this:
$scope.another =
function(fn){
userService.getInfo().success(function(data){
fn(data);
});
};
var data = $scope.another(function(doSomething) {
alert(doSomething);
return doSomething;
};
I need to call an async function (with loop) for multiple values and wait for those results. Right now I'm using the following code:
(function(){
var when_done = function(r){ alert("Completed. Sum of lengths is: [" + r + "]"); }; // call when ready
var datain = ['google','facebook','youtube','twitter']; // the data to be parsed
var response = {pending:0, fordone:false, data:0}; // control object, "data" holds summed response lengths
response.cb = function(){
// if there are pending requests, or the loop isn't ready yet do nothing
if(response.pending||!response.fordone) return;
// otherwise alert.
return when_done.call(null,response.data);
}
for(var i=0; i<datain; i++)(function(i){
response.pending++; // increment pending requests count
$.ajax({url:'http://www.'+datain[i]+'.com', complete:function(r){
response.data+= (r.responseText.length);
response.pending--; // decrement pending requests count
response.cb(); // call the callback
}});
}(i));
response.fordone = true; // mark the loop as done
response.cb(); // call the callback
}());
This isn't all very elegant but it does the job.
Is there any better way to do it? Perhaps a wrapper?
Async JS to the rescue (for both client-side and server-side JavaScript)! Your code may look like this (after including async.js):
var datain = ['google','facebook','youtube','twitter'];
var calls = [];
$.each(datain, function(i, el) {
calls.push( function(callback) {
$.ajax({
url : 'http://www.' + el +'.com',
error : function(e) {
callback(e);
},
success : function(r){
callback(null, r);
}
});
});
});
async.parallel(calls, function(err, result) {
/* This function will be called when all calls finish the job! */
/* err holds possible errors, while result is an array of all results */
});
By the way: async has some other really helpful functions.
By the way 2: note the use of $.each.
You can use the jQuery Deferred object for this purpose.
var def = $.when.apply(null, xhrs) with xhrs being an array containing the return values of your $.ajax() requests. Then you can register a callback def.done(function() { ... }); and use the arguments array-like object to access the responses of the various requests. to properly process them, remove your complete callback and add dataType: 'text' and use the following callback for done():
function() {
var response = Array.prototype.join.call(arguments, '');
// do something with response
}
I am writing a function which has to get the thumbnail information from a given video using the embed.ly API, however currently the function returns a value before it even got the JSON result from the API.
I am using the following code:
function getThumbnail(vUrl) {
var thumbnail = '';
var title = '';
var caption = '';
var content = '';
$.when( $.getJSON("http://api.embed.ly/1/oembed?key=:key&url="+vurl) ).then(function(data){
var thumbnail = data.thumbnail_url;
console.log(thumbnail);
return {
thumbnail:thumbnail,
vurl:vurl
}
});
}
However when using the Chrome Javascript console I can see that:
the function is called
undefined is returned
XHR request is finished
variable thumbnail content is shown in console
This is obviously the wrong order.
Any help is greatly appreciated!
Updated answer
getJSON returns a promise (a read-only deferred), so you can listen to it. But since you need some post-processing, you'd want to chain a then which allows you to alter the resolved value.
// Now using `then`
function getThumbnail(vUrl){
return $.getJSON("http://api.embed.ly/1/oembed?key=:key&url="+vurl).then(function(data){
return {
thumbnail:data.thumbnail_url,
vurl:vurl
}
});
}
//and in your call will listen for the custom deferred's done
getThumbnail('the_vurl_').then(function(returndata){
//received data!
});
Original answer
You can use a deferred object, and listen for the done().
function getThumbnail(vUrl) {
//create our deferred object
var def = $.Deferred();
//get our JSON and listen for done
$.getJSON("http://api.embed.ly/1/oembed?key=:key&url="+vurl)
.done(function(data){
//resolve the deferred, passing it our custom data
def.resolve({
thumbnail:data.thumbnail_url,
vurl:vurl
});
});
//return the deferred for listening
return def;
}
//and in your call will listen for the custom deferred's done
getThumbnail('the_vurl_')
.done(function(returndata){
//received data!
});
You could return $.getJSON's deferred to get the raw data. But because of "post-processing" into an object, the custom deferred is needed. You could also pass a callback to getThumbnail():
function getThumbnail(vUrl,callback) {
$.getJSON("http://api.embed.ly/1/oembed?key=:key&url="+vurl,function(returndata){
callback(returndata);
});
}
getThumbnail('the_vurl_',function(returndata){
//received data!
})
Using Async/Await
async function getThumbnail(vUrl) {
const data = await $.getJSON("http://api.embed.ly/1/oembed?key=:key&url="+vUrl);
return {
thumbnail:data.thumbnail_url,
vurl:vUrl
}
}
async function someFunction() {
let thumbNail = await getThumbnail('the_vurl_');
}
you can simple use $.getJSON's callback like following:
function result(res) {
console.log(res);
}
function getThumbnail(vUrl) {
var thumbnail = '';
var title = '';
var caption = '';
var content = '';
$.getJSON("http://api.embed.ly/1/oembed?key=:key&url="+vurl, function(data) {
var thumbnail = data.thumbnail_url;
console.log(thumbnail);
var result = {
thumbnail:thumbnail,
vurl:vurl
};
// passing the result to a function
getResult(result);
});
}
NOTE:
You see that I'm calling a function to pass the result, where you are trying to return, but you can't return result to caller function. Because, $.getJSON is asynchronous.
I am currently linking a javascript file to an html page, and upon using a function in that javascript file the return value essentially gets erased and shows up as undefined, even though in the function itself the value is defined (that was probably very confusing, i'll just show the code and it should make sense):
functions.js
function addActivity(contactNameSelected, username) {
var returnArray = [];
//post to .php
if(data.added)
{
var newEvent = [];
newEvent['id'] = data.id;
newEvent['date'] = formattedDate;
returnArray.push(true);
returnArray.push(newEvent);
return returnArray; //when i debug, this has a value and is a valid array at this point
}
else
{
returnArray.push(false);
returnArray.push(data.message); //when i debug, this has a value and is a valid array at this point
return returnArray;
}
}
home.html
var response = [];
response = addActivity(contactNameSelected, username); //although valid above, undefined here
if(response[0]) //error b/c response is undefined
{
//do stuff if successful
}
else{
//do other stuff if unsuccessful
}
If i just return a string it works fine, but for some reason if i attempt to return an array it is simply undefined. Why is this?
Thanks!
I'm guessing that the omitted '//post to .php' looks something like
$.post('...php', { ... }, function(data) {
if (data.added) ...
The AJAX response is handled by a callback function, which executes asynchronously. In other words, returnArray is populated well after addActivity has returned.
The return returnArray; statements are useless because you are returning a value from the callback, not from addActivity. The callback is invoked not by your code, but by XHR (in a different execution context) and its return value is discarded.
To properly pass your data back in asynchronous style, we need to tweak your code.
function addActivity(contactNameSelected, username, callback) {
$.post('...', { ... }, function(data) {
var returnArray=[];
if(data.added)
{
...
}
else
{
...
}
callback(returnArray);
});
}
addActivity(contactNameSelected, username, function(response) {
if(response[0])
{
...
}
else
{
...
}
});