Getting Undefined Variable in Javascript - javascript

UPDATED CODE: i, I'm new to Javascript programming and getting an undefined variable when trying to assign a new variable from a method.
I'm using node.js and creating a redis server using the redis-client in the "client variable".
var redis = require("redis");
var client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err); });
var numberPosts;
client.get("global:nextPostId", function(err, replies) {
numberPosts = replies;
console.log(numberPosts);
});
console.log(numberPosts);
When I call console.log inside the call back function it returns the proper value, however when I call the console.log outside of the callback function it returns "undefined". I'm trying to assign the value that is inside the callback function to the global variable numberPosts.
Any help is much appreciated, thanks.
Matt

I believe this will work:
client.get("global:nextPostId", function (err, reply) {
console.log("Number of posts: " + reply.toString());
})
The AJAX call is asynchronous so it doesn't have return value.. instead you have to use callback function and only there you have the value returned by the server method.
Edit: to assign the return value to global variable, first declare global variable:
var _numOfPosts = "";
Then:
client.get("global:nextPostId", function (err, reply) {
_numOfPosts = reply.toString());
})
However, the value won't be available until the AJAX call is finished so your original code can't work. There is not direct return value to store.
You can set timer to some reasonable response time, then have the code using the global variable in there.
Edit II: in order to call the method again once it's finished, have such code:
var _nextPostCallCount = 0;
function GetNextPost() {
//debug
console.log("GetNextPost called already " + _nextPostCallCount + " times");
//sanity check:
if (_nextPostCallCount > 1000) {
console.log("too many times, aborting");
return;
}
//invoke method:
client.get("global:nextPostId", function(err, replies) {
numberPosts = parseInt(replies.toString(), 10);
console.log("num of replies #" + (_nextPostCallCount + 1) + ": " + numberPosts);
//stop condition here.... for example if replies are 0
if (!isNaN(numberPosts) && numberPosts > 0)
GetNextPost();
});
//add to counter:
_nextPostCallCount++;
}
GetNextPost();
This will call the method over and over until the result is 0 or you pass some hard coded limit to prevent endless loop.

Try this instead to see errors:
var redis = require("redis");
client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err); });
//note the error logging
var numberPosts = client.get("global:nextPostId", function (error, response) {
if (error) {
console.log("async: " + error);
} else {
console.log("programming: " + response);
}
});
console.log("is lotsa fun: " + numberPosts);
As Shadow Wizard has pointed out you are trying to use numberPosts before there is something in it, as client.get() hasn't returned anything.
Read this to get a handle on node.js flow:
http://www.scribd.com/doc/40366684/Nodejs-Controlling-Flow

I was facing the the same issue when I applied the MVC framework.
To solve the problem, I employed the render function.
In the posts Model
exports.get = function(id,render) {
client.incr('post:id:'+id, function(err, reply) {
render(reply);
});
};
In the posts Controller
exports.get = function(req, res) {
posts.get('001', function (data){res.render('index',{post:data});});
};

Related

NodeJS Express: How can I get my object to build completely before sending it in the response?

I am trying to build a result_arr of location objects to send as a response, but I am not sure how to send the response only when the entire array has been built. The response contains an empty array, but result_arr array is filled after the response has already been sent.
function handle_getLocations(req, res, done){
var con_id = req.body["contractor_id"];
console.log("Contractor ID :" + con_id.toString());
var result_arr = new Array();
employee.getActiveByContractor(con_id, function(err, employees){
if (err) {
console.log("Logging error in json:\n");
res.json({"code" : 100, "status" : "Error in connection database"});
return;
};
if(employees.length === 0) done(null);
for(var i=0;i<employees.length;i++){
assignment.getLocationsByEmployeeID(employees[i].employee_id, function(err, locations){
if (err) {
console.log("Logging error in json:\n");
res.json({"code" : 100, "status" : "Error in connection database"});
return;
};
console.log("Number of locations: " + locations.length.toString());
for(var j=0;j<locations.length;j++){
console.log("Assignment is: " + locations[j].assignment_id.toString());
location.getAllByID(locations[j].location_id, function(err, loc){
if (err) {
console.log("Logging error in json:\n");
res.json({"code" : 100, "status" : "Error in connection database"});
return;
};
var loc_obj = {};
loc_obj.display_name = loc[0].display_name;
loc_obj.location_id = loc[0].location_id;
console.log("Location is: " + loc_obj.display_name);
console.log("Location ID is: " + loc_obj.location_id.toString());
result_arr.push(loc_obj);
console.log(result_arr);
done(result_arr);
});
};
});
};
});
};
I know that in nodejs the idea is to not make blocking calls, but I am not sure how to make sure all of the information is sent in the response.
You are calling many asynchronous functions in the loop and do not have any logic to check when all they are completed to send the response back to the client.
I modified your code a bit to add the logic in VannilaJS way which is very messy below but working code.
Anyways I would suggest you to use promise based/asynchronous modules
like async, bluebird etc to handle this nicely. Using them, you
can improve readability and easy maintainability in your code to get
rid of callback hells and other disadvantages.
async http://caolan.github.io/async/
bluebird https://github.com/petkaantonov/bluebird
You can read more about this on the below link,
https://strongloop.com/strongblog/node-js-callback-hell-promises-generators/
function handle_getLocations(req, res, done){
var con_id = req.body["contractor_id"];
console.log("Contractor ID :" + con_id.toString());
var result_arr = new Array();
employee.getActiveByContractor(con_id, function(err, employees){
if (err) {
console.log("Logging error in json:\n");
res.json({"code" : 100, "status" : "Error in connection database"});
return;
};
if(employees.length === 0) done(null);
var employeesChecked = 0;
var errors = [];
function sendResponse(){
if(employeesChecked === employees.length) {
res.json(result_arr);
//done(result_arr); // If required, uncomment this line and comment the above line
}
}
for(var i=0;i<employees.length;i++){
assignment.getLocationsByEmployeeID(employees[i].employee_id, function(err, locations){
var locationsChecked = 0;
if (err) {
console.log(err);
errors.push(err);
++employeesChecked;
sendResponse();
} else {
console.log("Number of locations: " + locations.length.toString());
for(var j=0;j<locations.length;j++){
console.log("Assignment is: " + locations[j].assignment_id.toString());
location.getAllByID(locations[j].location_id, function(err, loc){
++locationsChecked;
if (err) {
console.log(err);
errors.push(err);
} else {
var loc_obj = {};
loc_obj.display_name = loc[0].display_name;
loc_obj.location_id = loc[0].location_id;
console.log("Location is: " + loc_obj.display_name);
console.log("Location ID is: " + loc_obj.location_id.toString());
result_arr.push(loc_obj);
console.log(result_arr);
}
if(locationsChecked === locations.length) {
++employeesChecked;
}
sendResponse();
});
}
}
});
}
});
}
In order not to consume much time during the request-response life time, you need to separate each logic in a single endpoint, but sometimes as your case, you may need to hit the database more than a time to fetch data that depends on another, so assuming that employee.getActiveByContractor returning promise and as it's an async method so you need to to chain it with .then like this:
employee.getActiveByContractor(con_id)
.then(function(employees) {
Also, you my need to read about Promise.
As Basim says, this is a good time to use Promises.
getLocationsByEmployeeID and getAllByID are async so they won't be done by the time the loop is finished and you send your response.
Promises are built into the latest Node.js version.
Learn here: https://www.udacity.com/course/javascript-promises--ud898
Suggestion:
Create promise wrappers for getLocationsByEmployeeID and getAllByID
Use Promise.all to make sure every getLocationsByEmployeeID and getAllByID are complete
return your http response within Promise.all's "success" callback

JavaScript/node.js: Getting NULL when trying to access an object's property outside a certain function

I have the code snippet bellow which actually is a function that makes a query on a SQL database(used tedious for that).
All I want is to get the data from DB and use them on a web-page.
The issue is that: inside the request.on()... I'm calling date.setMyData() function. Still inside the request.on('row', function(columns)....if calling console.log(date.getMyData()) it successfully returns my data.
BUT, if trying to call date.getMyData outside the request.on('row', function(columns) ...I get NULL...
Is there anything that I'm missing here?
var date = new DBData();
function executeStatement() {
request = new Request(queryString, function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
});
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
date.setMyData(columns);
//WHY THIS CODE RETURNS MY DATA?
console.log(date.getMyData());
}
});
});
request.on('done', function(rowCount, more) {
console.log(rowCount + ' rows returned');
});
connection.execSql(request);
}
function DBData(){
var myData = null;
this.setMyData = function(obiect){
myData = obiect;
};
this.getMyData = function(){
return myData;
};
};
console.log(date.getMyData()); //WHY I GET 'NULL' HERE?
When you run that code, the order of execution will be
var date = new DBData()
console.log(date.getMyData()) // null at this point
// end of execution
The function executeStatement() gets defined, but it is not executed right away. It will be presumably executed at a later time when you call it, at which point it will populate your 'var date', hence it will display the correct data correctly when you console.log(date.getMydata()) inside the callback of executeStatement().

Cannot pass variable in Javascript

I'm trying to scrape data from a word document with node.js.
My current problem is that the below console log will return the value inside the juice block as the appropriate varaible. If I move that to outside the juice block it is completely lost. I tried putting return
function getMargin(id, content){
var newMargin = content.css("margin-left");
if(newMargin === undefined){
var htmlOfTarget = content.toString(),
whereToCut = theRaw.indexOf("<div class=WordSection1>");
fs.writeFile("bin/temp/temp_" + id + ".htm", theRaw.slice(0, whereToCut) + htmlOfTarget + "</body> </html>", function (err){
if (err) {
throw err;
}
});
juice("bin/temp/temp_" + id + ".htm", function (err, html) {
if (err) {
throw err;
}
var innerLoad = cheerio.load(html);
newMargin = innerLoad("p").css("margin-left");
console.log(newMargin); // THIS newMargin AS VALUE
});
}
console.log(newMargin);//THIS RETURNS newMargin UNDEFINED
return newMargin;
}
I think the problem lies with fs.write and juice being Asyc functions. I just have no idea how to get around it. I have to be able to call getMargin at certain points, in a sequential order.
As mentioned in comment, change your program flow to run in callbacks, after async code has completed...
// accept callback as parameter, and run it after async methods complete...
function getMargin(id, content, callback){
var newMargin = content.css("margin-left");
if(newMargin === undefined){
var htmlOfTarget = content.toString(),
whereToCut = theRaw.indexOf("<div class=WordSection1>");
fs.writeFile("bin/temp/temp_" + id + ".htm", theRaw.slice(0, whereToCut) + htmlOfTarget + "</body> </html>", function (err){
if (err) {
throw err;
}
// move the juice call inside the callback of the file write operation
juice("bin/temp/temp_" + id + ".htm", function (err, html) {
if (err) {
throw err;
}
var innerLoad = cheerio.load(html);
newMargin = innerLoad("p").css("margin-left");
console.log(newMargin); // THIS newMargin AS VALUE
// now run the callback passed in the beginning...
callback();
});
});
}
}
// call getMargin with callback to run once complete...
getMargin("myId", "myContent", function(){
// continue program execution in here....
});

Node/Express - How to wait until For Loop is over to respond with JSON

I have a function in my express app that makes multiple queries within a For Loop and I need to design a callback that responds with JSON when the loop is finished. But, I'm not sure how to do this in Node yet. Here is what I have so far, but it's not yet working...
exports.contacts_create = function(req, res) {
var contacts = req.body;
(function(res, contacts) {
for (var property in contacts) { // for each contact, save to db
if( !isNaN(property) ) {
contact = contacts[property];
var newContact = new Contact(contact);
newContact.user = req.user.id
newContact.save(function(err) {
if (err) { console.log(err) };
}); // .save
}; // if !isNAN
}; // for
self.response();
})(); // function
}; // contacts_create
exports.response = function(req, res, success) {
res.json('finished');
};
There are a few problems with your code besides just the callback structure.
var contacts = req.body;
(function(res, contacts) {
...
})(); // function
^ you are redefining contacts and res in the parameter list, but not passing in any arguments, so inside your function res and contacts will be undefined.
Also, not sure where your self variable is coming from, but maybe you defined that elsewhere.
As to the callback structure, you're looking for something like this (assuming contacts is an Array):
exports.contacts_create = function(req, res) {
var contacts = req.body;
var iterator = function (i) {
if (i >= contacts.length) {
res.json('finished'); // or call self.response() or whatever
return;
}
contact = contacts[i];
var newContact = new Contact(contact);
newContact.user = req.user.id
newContact.save(function(err) {
if (err)
console.log(err); //if this is really a failure, you should call response here and return
iterator(i + 1); //re-call this function with the next index
});
};
iterator(0); //start the async "for" loop
};
However, you may want to consider performing your database saves in parallel. Something like this:
var savesPending = contacts.length;
var saveCallback = function (i, err) {
if (err)
console.log('Saving contact ' + i + ' failed.');
if (--savesPending === 0)
res.json('finished');
};
for (var i in contacts) {
...
newContact.save(saveCallback.bind(null, i));
}
This way you don't have to wait for each save to complete before starting the next round-trip to the database.
If you're unfamiliar with why I used saveCallback.bind(null, i), it's basically so the callback can know which contact failed in the event of an error. See Function.prototype.bind if you need a reference.

How to return the result of a websql function

I am using the websql database in my webapplication to store some data from actual db and fetch it through websql api.
Currently the call is asynchronous, i.e, the result is updated after all the tasks are finished.
I want to change it to synchronous i.e, step by step executed. Here is the function i am calling from js code
function fetch(model, id, success, error) {
var tableName = model.prototype.tableName,
sql = 'SELECT * FROM ' + tableName + ' WHERE ' + tableName + '_id = ?';
if (db) {
// websql
db.readTransaction(function (tx) {
tx.executeSql(sql, [id], function (tr, result) {
if (result.rows.length === 0) {
return null;
} else {
success(transform(model, result.rows.item(0)));
}
}, error);
});
} else {
// localStorage
throw 'Not implemented';
}
}
am calling this from a line of code.
OB.Dal.fetch(OB.Model.BusinessPartner, businessPartnerId);
How can i return the result of the method fetch() and assign it to some variable in the next step. some thing like
var bpartner = OB.Dal.fetch(OB.Model.BusinessPartner, businessPartnerId);
model.set('bp', bpartner);
--
Thanks in advance!

Categories