this function gets a question from a database and is supposed to return it.
The database is a Parse object(https://www.parse.com/docs/js_guide). As indicated in the comments in the code the question is accessible from within the success function of the db call but not from outside it and simply putting the return statement inside the success block doesn't work either.
Code below. Any suggestions?
function getQuest(){
var Question = Parse.Object.extend("Question");
var query = new Parse.Query("Question");
var questlist = [];
var newquestion;
//get list of questions if chosen track is python or java. track is set globally
if (track == "python")
{
query.equalTo("track", "xstsysysus7");
} else if (track == "java"){
query.equalTo("track", "XAWqBgxFAP");
}
query.find({
success: function(questions){
// return list of questions
var i = Math.floor(Math.random()*10);
newquestion = questions[i].get('question');
console.log(newquestion); // works here
},
error: function(error){
console.log(error.message);
}
});
console.log(newquestion); //returns undefined here
return newquestion;
}
You cannot return from the callback method like this, this is an async issue, you should use a callback method to get your variable out from the method
function getQuest(callback){
var Question = Parse.Object.extend("Question");
var query = new Parse.Query("Question");
var questlist = [];
var newquestion;
//get list of questions if chosen track is python or java. track is set globally
if (track == "python")
{
query.equalTo("track", "xstsysysus7");
} else if (track == "java"){
query.equalTo("track", "XAWqBgxFAP");
}
query.find({
success: function(questions){
// return list of questions
var i = Math.floor(Math.random()*10);
newquestion = questions[i].get('question');
//call the callback method here and pass your variable as a param
if(callback != null && callback != undefined){
callback(newquestion);
}
},
error: function(error){
console.log(error.message);
}
});
}
Now you can call your getQuest method just like this instead of using var newQ = getQuest()
getQuest(function(newQuestion){
// do your stuff with newQuestion
})
The callbacks (success and error), are asynchronous. They have probably not been executed before your function returns.
Related
im wondering if i can get some help here, im not a skilled coder by far, but im trying to retrieve results outside the function and the result in log im getting is Undefined
var pricecrex;
getDataFromAPI("https://api.crex24.com/CryptoExchangeService/BotPublic/ReturnTicker?request=[NamePairs=BTC_WAGE]",
true,
function(data){
var resultcrex = JSON.parse(data);
if (resultcrex !== "undefined") {
if (resultcrex) {
var pricecrex = resultcrex.Tickers[0].Last
}
else {
msg.reply("0")
}
}
}
);
console.log(pricecrex);
It is because Ajax requests are async. console.log() gets executed before response is received from request, and thus before setting value in pricecrex. So you were getting undefined.
var pricecrex;
getDataFromAPI("https://api.crex24.com/CryptoExchangeService/BotPublic/ReturnTicker?request=[NamePairs=BTC_WAGE]",
true, function(data) {
var resultcrex = JSON.parse(data);
if (resultcrex !== "undefined") {
if (resultcrex) {
pricecrex = resultcrex.Tickers[0].Last;
print(pricecrex);
}
else {
msg.reply("0")
}
}
}
);
function print(data) {
console.log(data);
}
The nature of Javascript is continue running code once an asynchronous function has been started. So you run getDataFromAPI(), and then while that's running, the interpreter goes to the next piece of code, which is your console.log(pricecrex).
So you can either run the console.log(pricecrex) directly in the callback, function(data){}, or to keep things cleaner, wrap your console.log() within a function and call that function from within your callback.
Example:
let someVar;
someAsync('someurl.com', (data) =>{
someVar = data;
callTheConsole()
})
function callTheConsole(){
console.log(someVar)
}
Instead of assigning the value to the variable. Pass it to another function. Thus the value passed to another function is not 'undefined'.
function validation(pricecrex){
console.log(pricecrex);
}
getDataFromAPI("https://api.crex24.com/CryptoExchangeService/BotPublic/ReturnTicker?request=[NamePairs=BTC_WAGE]",
true,
function(data){
var resultcrex = JSON.parse(data);
if (resultcrex !== "undefined") {
if (resultcrex) {
var pricecrex = resultcrex.Tickers[0].Last;
validation(pricecrex);
}
else {
msg.reply("0")
}
}
}
);
For more information, check out the below link. Detailed information with examples is available.
How to return the response from an asynchronous call??
working with node.js Q promises library i am in doubt that is it useful with recursively calling a function. I had tried two approaches to solve my problem.In 1st approach i tried to returns directly from recursive function And in 2nd approach i tried with Q promise library.
Here is my code from where i am calling that recursive function and expecting response here.
function getSearchedUserInTree(userId,body){
var deferred = Q.defer();
var loggedInUserId = userId;
var searchUserIdSql = "SELECT rc.user_id,CAST(b.node_id AS CHAR) AS node_id FROM refer_codes AS rc LEFT JOIN btrees AS b ON b.user_id=rc.user_id WHERE rc.refer_code='"+body.refer_code+"'";
connection.query(searchUserIdSql, function (err, result,field) {
var getLoggedInNode = "SELECT CAST(b.node_id AS CHAR) AS node_id FROM btrees as b WHERE b.user_id='"+loggedInUserId+"'";
connection.query(getLoggedInNode, function (err, loggedResult,field) {
helper.trackRelation(loggedResult[0].node_id,result[0].node_id,function(err,relationResult){
if(err) throw err;
deferred.resolve(relationResult);
});
});
});
return deferred.promise;
}
1st approach to get return from "trackRelation()" function with promises.
function trackRelation(parentNode,childNode){
var deferred = Q.defer();
var childNodeId = bigInt(""+childNode+"");
var parentNodeId = bigInt(""+parentNode+"");
if(bigInt(childNodeId).compare(parentNodeId) == 0){
var childSql = "SELECT * FROM users WHERE id='"+childNodeId.toString()+"'";
connection.query(childSql,function(err,packResult,field){
console.log(packResult);
deferred.resolve({status:200,message:'success',packResult});
});
}else{
/* Detact position */
if(bigInt(childNodeId).mod(2) == 0){
var tempParentNodeId = bigInt(childNodeId).divide(2);
}else{
var subResult = bigInt(childNodeId).subtract(1);
var tempParentNodeId = subResult.divide(2);
}
/** If reached at top but parent not found **/
if(bigInt(tempParentNodeId).compare(1) == 0){
var childSql = "SELECT * FROM users WHERE id='"+tempParentNodeId.toString()+"'";
connection.query(childSql,function(err,packResult,field){
console.log(packResult);
deferred.resolve({status:200,message:'success',packResult});
});
}else{
return trackRelation(parentNodeId,tempParentNodeId.toString());
}
}
return deferred.promise;
}
2nd approach to get return from recursively function with directly return value without promises.
function trackRelation(parentNode,childNode){
var deferred = Q.defer();
var childNodeId = bigInt(""+childNode+"");
var parentNodeId = bigInt(""+parentNode+"");
if(bigInt(childNodeId).compare(parentNodeId) == 0)
{
deferred.resolve({status:200,message:'success',topUserId:childNodeId.toString()});
return childNodeId.toString();
}else
{
/* Detact position */
if(bigInt(childNodeId).mod(2) == 0){
var tempParentNodeId = bigInt(childNodeId).divide(2);
}else
{
var subResult = bigInt(childNodeId).subtract(1);
var tempParentNodeId = subResult.divide(2);
}
/** If reached at top but parent not found **/
if(bigInt(tempParentNodeId).compare(1) == 0){
return tempParentNodeId.toString();
}else
{
return trackRelation(parentNodeId,tempParentNodeId.toString());
}
}
return deferred.promise;
}
I didn't get any response from both of these approaches. i tried to print values which i need in response in console and i got that value same as desired but unable to get that value in response.
You can't get the value back from a promise the way you get back from a callback.
Your method trackRelation returns a promise whose values should be accessed using the .then() method.
Example:
trackRelation(args).then(function(res){
//when the promise resolves, this method is called
}, function(err){
//when the promise rejects, this method is called
});
Check the API reference page here.
I am trying to fill an array with records from a mongoDB database using mongoose. When I am trying to fill the records. It shows an empty array outside the function even though I am declaring the outside the function. Below is the code.
var saveMessageToVariable = function(){
var records = [];
var spark_ids = [];
var obj = new Object();
Message.find().distinct("spark_id").exec(function(err,data) {
data.forEach(function (id) {
if(id != null)
spark_ids.push(id);
});
// console.log(spark_ids.length);
spark_ids.forEach(function(spark_id){
Message.findOne({"spark_id":spark_id}).sort({"date":-1}).exec(function(err,data){
obj.spark_id = data.spark_id;
obj.meesage = data.message;
obj.date = data.date;
obj.message_id = data._id;
records.push(obj);
});
});
});
console.log(records);
}
When I run this, the log is showing an empty array. How do I resolve this issue?
It's an asynchronous call and as soon as data is fetched from database control shifts to next line and therefore prints the initial value, I would prefer you to use a callback like this:
function(spark_id,callback){
Message.findOne({"spark_id":spark_id}).sort({"date":-1}).exec(function(err,data){
obj.spark_id = data.spark_id;
obj.meesage = data.message;
obj.date = data.date;
obj.message_id = data._id;
callback(obj);
});
}
function(obj)
{
records.push(obj);
}
You two other approachs for this:
1) use try and catch block.
2) use async and await keyword.
Cheers!
I don't have much experience with moongoose, but according to the docs it supports promises since Version 4.
Then this should work:
//I assume you'll need this more often
function notNull(value){ return value != null; }
//returns a promise of the records-Array
var saveMessageToVariable = function(){
//returns a promise of a formated message
function getMessage( spark_id ){
return Message.findOne({ spark_id })
.sort({ date: -1 })
//.exec()
.then( formatMessage )
}
function formatMessage( msg ){
return {
spark_id: msg.spark_id,
message: msg.message,
date: msg.date,
message_id: msg._id
}
}
return Message.find()
.distinct("spark_id")
//.exec()
.then(function( ids ){
//waits for all findOnes to complete, then returns an Array
return Promise.all(
ids.filter( notNull ).map( getMessage )
));
}
I'm not sure, wether you need exec() in this code or not. You should check that.
//usage
saveMessageToVariable.then(function(records){
console.log(records);
})
btw. saveMessageToVariable doesn't reflect at all what this function does. You should choose a better name.
I have a function with a return however in the function there is an async request which holds the value that is suppose to be returned by the function. I understand with the nature of async request the function will complete and not return a value while waiting on the async function to complete.
I attempted to use dojo deferred functions to have my function PostInformation() to return a value within the ajax request callback. I am having some issues and i am not sure where my issue is. Under is my code:
Dojo Deferred Function
function PostInformation(){
var hasErrors = false;
var containers = [dijit.byId("container1"), dijit.byId("container2")];
var Employee = {
//data
};
var def = new dojo.Deferred();
def = dojo.xhrPost({
url: 'hello',
content: Employee,
load: function (data) {
formErrors = {
"errors": true,
"fName": "123",
"surname": "456",
"oNames": "789",
"bSurname": "784585"
};
//formErrors = (JSON.parse(data)).formErrors;
$.each(formErrors, function (key, value) {
if (key == 'errors') {
hasErrors = value;
//console.log('hasErrors set to '+value);
}
});
if (hasErrors == true) {
for (var i = 0; i < containers.length; i++) {
var processingContainer = containers[i];
dojo.forEach(processingContainer.getChildren(), function (wid) {
var widgetName = wid.attr('id');
$.each(formErrors, function (key, value) {
if (key == widgetName && value.length > 0) {
var myWidget = dijit.byId(widgetName);
//var wdgName = dijit.byId(widgetName).attr("id");
var myWidgetValue = value;
myWidget.validator = function () {
//console.log('Attribute Name is :' + wdgName + ' Error Value is : ' + myWidgetValue);
//console.log(wdgName + " : "+myWidgetValue);
this.set("invalidMessage", myWidgetValue);
};
myWidget._hasBeenBlurred = true;
myWidget.validate();
}
});
});
}
}
console.log(hasErrors);
def.resolve(hasErrors);
},
error: function(err){
console.log(err);
def.reject(err);
}
});
def.then(function(data){
console.log('In the then function');
//alert('In the def.then and the results is : ' + data);
if(data == true){
return false;
}else{return true;}
},function(err){
return false;
alert('In the def.error and there has been an error ' + err);
});
//return the value of hasErrors here
};
Devdar, you are making heavy wether out of something quite simple. In particular, you don't need to loop through an object to access one of its properties, and the variable hasErrors is not really necessary.
Your code should simplify to something like this :
function PostInformation() {
var $containers = $("#container1, #container2");
var Employee = {
//data
};
return dojo.xhrPost({
url: 'hello',
content: Employee
}).then(function(data) {
data = JSON.parse(data);
var formErrors = data.formErrors;
if(formErrors.errors) {
$containers.each(function(i, c) {
$(c).children().each(function(wid) {
var val = formErrors[wid.id],
myWidget;
if(val) {
myWidget = dijit.byId(wid.id);
myWidget.validator = function() {
this.set("invalidMessage", val);
};
myWidget._hasBeenBlurred = true;
myWidget.validate();
}
});
});
//Send an enhanced error object down the "error" route
throw $.extend(formErrors, {
'message': 'PostInformation(): validation failure'
});
}
//Send the data object down the "success" route
return data;
});
};
PostInformation().then(function(data) {
console.log('PostInformation(): everything went OK');
//access/process `data` here if necessary
//and/or just display a nice "success" message to the user
}, function(err) {
console.error(err.message);
});
Barring mistakes on my part, this code should do everything you want and more. As with your own code, it processes the server's JSON response and returns a Promise, but that's where the similarity stops.
In your code, you seek to return a Promise which is eventually resolved with a boolean to indicate whether or not errors were detected. Whilst this will (if correctly written) meet your immediate needs, it is not the best Promise logic.
In my code, the Promise is resolved only if validation succeeds and rejected if validation fails for whatever reason. Not only is this logically correct behaviour for a Promise (success goes down the success route, and errors go down the error route) but as a bonus should (see note below) also allow you to pass more information to whetever function(s) eventually handle errors. I choose to pass the whole formErrors object enhanced with an error message, thus providing a great deal of freedom in the error handler to display/log/etc as much or as little as is appropriate, and with virtually no assumption inside PostInformation() as to what will happen subsequently. You currently believe that you will only read and act on the boolean formErrors.errors but it could be beneficial to pass as much error data as possible thus allowing yourself the freedom to change your mind at a later date without needing to change anything in PostInformation().
In this regard you can think of PostInformation() as an agent of the server-side service; and like that service, it can be written with incomplete knowledge (or maybe no knowledge at all) of how the (promise of) data/errors it delivers will be used by "consumer code".
NOTE: I have to admit that I'm not 100% familiar with Dojo's Promises, so I'm not sure that a JS plain object can be thrown in the way I indicate. I have found evidence but not proof that it can. For that reason, I am cautious above in saying "your code should simplify to something like this" Anyway, that issue aside, the principle of sending success down the success route and errors down the error route should still apply.
I'd suggest this where you create your own Deferred() object, return it from your PostInformation() function and then register .then() handlers on it so you can pick up the resolve or reject on your own Deferred object that happens inside the PostInformation() function.
The way you had it you were creating your own Deferred() object, but then immediately overwriting it with the xhrPost return result which meant def is now something else and you weren't returning your Deferred from PostInformation() so it can be used outside that function to track the progress.
function PostInformation() {
var hasErrors = false;
var containers = [dijit.byId("container1"), dijit.byId("container2")];
var Employee = {
//data
};
var def = new dojo.Deferred();
dojo.xhrPost({
url: 'hello',
content: Employee,
load: function (data) {
formErrors = {
"errors": true,
"fName": "123",
"surname": "456",
"oNames": "789",
"bSurname": "784585"
};
//formErrors = (JSON.parse(data)).formErrors;
$.each(formErrors, function (key, value) {
if (key == 'errors') {
hasErrors = value;
//console.log('hasErrors set to '+value);
}
});
if (hasErrors == true) {
for (var i = 0; i < containers.length; i++) {
var processingContainer = containers[i];
dojo.forEach(processingContainer.getChildren(), function (wid) {
var widgetName = wid.attr('id');
$.each(formErrors, function (key, value) {
if (key == widgetName && value.length > 0) {
var myWidget = dijit.byId(widgetName);
//var wdgName = dijit.byId(widgetName).attr("id");
var myWidgetValue = value;
myWidget.validator = function () {
//console.log('Attribute Name is :' + wdgName + ' Error Value is : ' + myWidgetValue);
//console.log(wdgName + " : "+myWidgetValue);
this.set("invalidMessage", myWidgetValue);
};
myWidget._hasBeenBlurred = true;
myWidget.validate();
}
});
});
}
}
console.log(hasErrors);
def.resolve(hasErrors);
},
error: function (err) {
console.log(err);
def.reject(err);
}
});
return def.promise;
};
PostInformation().then(function (data) {
console.log('In the then function');
// process data value here which will contain the value you resolved with
}, function(err)
// process an error in the ajax result here
});
I think this is more of an issue with design of the function then.
Since the xHR call is asynchronous, the postInformation shouldn't really return anything unless it's the Deferred object itself. An alternative option is to have postInformation do some sort of event publishing (dojo/topic), that other functions will subscribe to and know how to handle said events.
I have a rather simple getUser method that I'm having some trouble with. I am not deeply familiar with scopes and such in JS so this is giving me a head ache. Basically I want to fetch an object from the database and return it to the calling method:
function getUser(uid)
{
var result = null;
var userTable = tables.getTable('Users');
userTable.where({
userId: uid
}).read({
success: function (results) {
if (results.length > 0) {
result = results[0];
console.log('userid'+result.id);
}
}
});
console.log('userid-'+result.id); // undefined!!
return result;
}
Also, returning from inside the success doesn't return from getUser, but just the function defined inside. I tried "result = function(results)" as well but it stores the defined function and not the return value.
How am I supposed to do this?
I found a solution to this elsewhere. In practice (to the best of my understanding), it is not possible to do this within a JavaScript with asynchronous functions. What you need to do is create a recursion instead from inside the success handler.
Because the call to the database is asynchronous, your last two lines are executed (and hence result is undefined) before the call the database actually finishes. So you need to handle everything inside your success callback. Or, if your getUser() func is a helper, you could structure your code (without recursion) like this with a callback:
function insertOrWhateverCallingMethod()
{
var uid = 'blah';
getUser(uid,function(user) {
// Do something with the user object
});
}
function getUser(uid,callback)
{
var result = null;
var userTable = tables.getTable('Users');
userTable.where({
userId: uid
}).read({
success: function (results) {
if (results.length > 0) {
result = results[0];
console.log('userid'+result.id);
callback(result);
}
}
});
callback(null);
}
The code above assumes you're in a table script, where the tables object is available - if it's not you can pass it as a parameter to getUser().