Returned object is undefined, using dynamicHelpers - node.js

I've created an external file that's handling the dynamic helpers, which includes a bunch of functions that I want to be able to use from all my views.
In on of the functions I'm running a query and fetch tags from the database, which I want to use in my layout.jade file (that all other views is using). In the console, all seems ok. The query returns the tags object, but by some strange reason I can't return the object to the view, which gives me an error message telling me that "tags" is undefined".
This is the code in my file dynamicHelpers.js:
exports.tags = function(req, res){
var environment = require('../environment');
var service = require('../service');
service.init(environment);
var model = service.useModel('tag');
var query = model.Tag.find({});
query.exec(function (err, tags) {
if (err) {
console.log(err);
// do something
}
console.log(tags);
return tags;
});
}
in layout.jade i'm getting the object in this way (this shows undefined):
p
#{tags}
What I actually want to do is to loop through all the tags with 'each'. So a follow-up issue would be if this is allowed and possible (if 'tags' were not undefined)?
ul.tags
each tag in #{tags}
a(href='/tag/' + tag._id.toHexString())
li.tag= tag.name
UPDATE:
I've tried #Linus G Thiel's solution (see below), but can't get it to work (res.tags gets undefined). With console.log(tags) in the middleware, it prints out the object. However, in the dynamicHelper function below it gets undefined. Seems like res.tags doesn't get passed to the dynamicHelper by some reason.
dynamicHelpers.js:
exports.tags = function(req, res) {
console.log(req.tags); <--- undefined
return req.tags;
};
configuration.js:
module.exports = function(app, express, next){
app.configure(function() {
// lots of more app.use functions (eg. express.cookieParser());)
// ...
app.use(function(req, res, next) {
var environment = require('./environment');
var service = require('./service');
service.init(environment);
var model = service.useModel('tag');
var query = model.Tag.find({});
query.exec(function (err, tags) {
if (err) {
return next(err);
}
req.tags = tags;
next();
console.log(req.tags); <--- works fine
});
});
});
};

As #Exploit says in his comment, your tags function makes an async call to query.exec, which will finish after your tags function has returned. Express' helpers and dynamicHelpers can't be async, so you need to refactor this somehow. One way would be to put it on req in an earlier middleware or route, and then have a simple dynamicHelper which returns that:
dynamicHelpers.js:
exports.tags = function(req, res) {
return req.tags;
};
Middleware (you might not want to do this for all routes, you could look into e.g. Route specific middleware or Route param pre-conditions):
app.use(function(req, res, next) {
var environment = require('../environment');
var service = require('../service');
service.init(environment);
var model = service.useModel('tag');
var query = model.Tag.find({});
query.exec(function (err, tags) {
if (err) {
return next(err);
}
req.tags = tags;
next();
});
});

It's kinda dirty but you can do this to wait for tags to be set. The solution Linus G Thiel provided is better though because this will block your application.
tags: function(req, res) {
var environment = require('../environment');
var service = require('../service');
service.init(environment);
var model = service.useModel('tag');
var query = model.Tag.find({});
var _tags = false;
query.exec(function (err, tags) {
if (err) {
console.log(err);
// do something
}
console.log(tags);
_tags = tags;
});
while(_tags == false);
return _tags;
}
Have you tried it like this?
exports = function(app) {
app.dynamicHelpers({
tags: function(req, res) {
var environment = require('../environment');
var service = require('../service');
service.init(environment);
var model = service.useModel('tag');
var query = model.Tag.find({});
query.exec(function (err, tags) {
if (err) {
console.log(err);
// do something
}
console.log(tags);
return tags;
});
}
});
}
require("helpers")(app);

You need to defined the middleware before the other routes
module.exports = function(app, express, next){
app.configure(function() {
app.use(function(req, res, next) {
var environment = require('./environment');
var service = require('./service');
service.init(environment);
var model = service.useModel('tag');
var query = model.Tag.find({});
query.exec(function (err, tags) {
if (err) {
return next(err);
}
req.tags = tags;
next();
console.log(req.tags); <--- works fine
});
});
// lots of more app.use functions (eg. express.cookieParser());)
// ...
});
};

Related

Gather multiple functions output on single route call and render to html in nodejs

Newbie to nodejs,trying to execute multiple functions output to html using nodejs,express and mysql as backend.Need to execute 20 functions on single routing call to combine the output of 20 functions and render as json to html.
My app.js function
var express = require('express');
var router = express.Router();
var path = require('path');
var app = express();
var todo = require('./modules/first');
var todo1 = require('./modules/second');
var connection = require('./connection');
connection.init();
app.get('/', function(req,res,next) {
Promise.all([todo.class1.getUsrCnt(),todo.class1.getTotlAmt(),todo.class1.getTotlOrdrCnt(),todo.class1.getTotlCntRcds(),todo.class1.getTotlScsRcds(),todo.class1.getTotlFailRcds(),todo.class1.getTotlAmtRcds()])
.then(function(allData) {
res.addHeader("Access-Control-Allow-Origin", "http://hostname:8183/");
res.json({ message3: allData });
});
res.send(send response to html);
})
app.get('/second', function(req,res,next) {
Promise.all([todo1.class2.getUsr........])
.then(function(allData) {
res.addHeader("Access-Control-Allow-Origin", "http://hostname:8183/");
res.json({ message3: allData });
});
res.send(send response to html);
})
var server = app.listen(8183, function(){
console.log('Server listening on port '+ server.address().port)
});
My todo.js is
var connection = require('../connection');
var data = {},obj={};
var d = new Date();
var month = d.getMonth() + 1;
var year = d.getFullYear();
obj.getUsrCnt = function getUsrCnt(callback) {
connection.acquire(function(err, con) {
con.query(query1, function(err, result) {
con.release();
data.usrs_cnt = result[0].some;
})
});
}
obj.getTotlAmt = function getTotlAmt(callback) {
connection.acquire(function(err, con) {
con.query(query2, function(err, result) {
con.release();
data.total_amt = result[0].some1;
})
});
}
obj.getTotlOrdrCnt = function getTotlOrdrCnt(callback) {
connection.acquire(function(err, con) {
con.query(query3, function(err, result) {
con.release();
data.total_orders = result[0].some2;
})
});
}
.
.
. functions go on
exports.class1 = obj;
Getting undefined in the promise all and unable to render to the html file.
Not sure about the code you wrote, but as I understand you want to call all the functions, get all the results and return back to the user?
so you can use many libraries that waits for several calls for example, promise based:
Promise.all([todo.getUsrCnt('dontcare'), todo.getTotlAmt('dontcate')])
.then(function(allData) {
// All data available here in the order it was called.
});
as for your updated code, you are not returning the data as promises, you assigning it to the local variable.
this is how your methods should look:
obj.getUsrCnt = function getUsrCnt(callback) {
var promise = new Promise(function(resolve, reject) {
connection.acquire(function(err, con) {
if(err) {
return reject(err);
}
con.query(query1, function(err, result) {
con.release();
resolve(result[0].some);
})
});
});
return promise;
}
as you can see here, I am creating a new promise and returning it in the main function.
Inside the new promise I have 2 methods: "resolve", "reject"
one is for the data and one is for errors.
so when you use the promise like this:
returnedPromise.then(function(data) {
//this data is what we got from resolve
}).catch(function(err) {
//this err is what we got from reject
});
you can see that a promise can or resolved or rejected,
do this to all the methods, and then you start seeing data

Query data with NodeJS#find() function from a MongoDB

I'm trying to retrieve data from a MongoDB with Node. Here is my code:
var MongoClient = require('mongodb').MongoClient;
var ObjectId = require('mongodb').ObjectId;
var url = 'mongodb://localhost:27017/test';
module.exports.get = function (req, res) {
//console.log(req.params.id)
//prints 1
var query = {};
query['id'] = req.params.id;
MongoClient.connect(url, function (err, db) {
db.collection('events')
.find(query)
.limit(1)
.next( function (err, event) {
if (err) {
res.status(500).send('Could not bring the resource requested!');
}
if (event) {
res.setHeader('Content-Type', 'application/json');
res.send(event);
}
else {
res.status(404).send('Can\'t find the resource you\'re looking for');
}
// db.close();
});
})
}
In my db, I have a document that has its own id field, different from _id.
Problem is with this line of code: query['id'] = req.params.id;
Using this, I get event = null.
But, when I change this to: query['id'] = 1;, I get the data that I'm looking for. I don't know where the problem is.
Managed to solve the problem. I was getting this because of req.params.id that is a String.
I used Number(req.params.id) and it's working.

node/express server. parameter is undefined

What is going wrong with my string parameter?
var express = require('express');
var app = module.exports = express();
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var braintree = require("braintree");
Schema = mongoose.Schema;
var user = require('../shared/userFunctions.js')
//register functions
app.register = function(api) {
api.get('get_client_token', generateClientToken);
api.get('find_customer', findCustomer);
api.post('checkout', checkout);
api.post('create_customer', createCustomer);
api.post('create_payment_method', newPaymentMethod);
}
The checkout function is where I call the local function with user.getuser
function checkout(request, response) {
var email = request.body.email;
var nonce = request.body.payment_method_nonce;
//var nonce = req.param("payment_method_nonce");
var amount = request.body.amount;
// Use payment method nonce here
gateway.transaction.sale({
amount: amount,
paymentMethodNonce: nonce,
}, function (err, result) {
if(err){
return response.send(500, "Checkout failed")
}
/* request.add({"amount": 10})
request = nonce;
newPaymentMethod(request);*/
/* return res.send(200, "Checkout Success")*/
});
user.getuser(email, function(u){
console.log("returning user: " + JSON.stringify(u))
return response.send(200, JSON.stringify(u))
})
}
If I hard core the email address into the mongoose query, it returns the user. What gives? Please give advice on my node async style. I am still new to it, but sometimes error first fucntions don't work and sometimes I need "next". The static email works but is my style the problem?
exports.getuser = function(email, res) {
var db = mongoose.connection;
mongoose.connect(process.env.MongoConnectionString);
db.on('error', function () {
});
db.once('open', function callback() {
console.log("Sucessfully Logged into mongo");
User.findOne({email:email}, function (err, user, next) {
if (err) {
mongoose.disconnect();
return next(err);
}
mongoose.disconnect();
console.log("Sending user response");
if(!user){
console.log("failed to get user")
return
}
return res(user);
});
});
EDIT
This function is responsible for calling the internal function. It seems to work exactly like the checkout function, except for its magical ability to work correctly.
function getUser(request, response) {
var email = request.param('email');
user.getuser(email, function(user){
return response.send(200, JSON.stringify(user))
})
};
Using a REST client so I assure you that body/params is not the problem. Thanks for the help thus far.
you can check your paratmeter in your api like this :
var password = req.body.passwordBrow || '';
var uidUser = req.body.uidUser || '';
and then check it :
if(password && uidUser){
// here you can log your parameters
}else{
// the parameter is undefined, so you need to check your request in the client
res.json({
status : "not_ok",
result : "empty_data",
resultType : serverConst.EmptyParams
});
}
hope it helps you.

node - continuation-local-storage

I am attempting to use the continuation-local-storage package to access the current express request/response from a point where that is not readily accessible.
I created the following middleware:
var createNamespace = require('continuation-local-storage').createNamespace,
getNamespace = require('continuation-local-storage').getNamespace;
const domain = 'ns.cls';
exports.configure = function(app) {
createNamespace(domain);
app.use(function(req, res, next) {
exports.set(req, res, "callcontext", { req, res });
next();
});
};
exports.set = function(req, res, name, value) {
var namespace = getNamespace(domain);
namespace.bindEmitter(req);
namespace.bindEmitter(res);
namespace.run(() => namespace.set(name, value));
};
exports.get = function(name) {
var namespace = getNamespace(domain);
return namespace.get(name);
};
exports.getCallContext = function() {
return exports.get("callcontext");
};
However when I attempt to access the context it is undefined:
var localStorage = require('../middleware/local-storage');
module.exports = function(doc, ctx) {
var callContext = localStorage.getCallContext();
console.log("value: " + callContext);
};
Does anyone have any ideas?
Thanks in advance,
Mark
createNameSpace should be called once. Also, you have an error on line
exports.set(req, res, "callcontext", { req, res });
should be something like
exports.set(req, res, "callcontext", { key: value });
This is the way I am using it:
to set
var session = require('continuation-local-storage').createNamespace('session')
app.use(function(req, res, next) {
session.bindEmitter(req);
session.bindEmitter(res);
session.run(function() {
session.set('req', req);
next();
});
});
to get
var session = require('continuation-local-storage').getNamespace('session')
session.get('req')

Create a nodejs module from a mongodb document to act as a model

I want to create a model by encapsulation inside a node module a mongodb document with some functionality that has to do with that document. I was wondering what's the best pratice for doing this kind of thing?
also, is it a good idea to share the db instance with the global variable? if not how should I do it? (i'm using mongoskin)
The way i would like it to work:
1. get document from mongo -> pass to module constructor
2. get json via post request -> pass to the same module construсtor
i thought about something like this(using express):
Module(user.js):
var mongo = global.mongo;
var db = global.db;
db.bind('users');
function User(user, callback) {
var self = this;
self.name = user.name;
self.email = user.email;
if(user._id) {
self._id = user._id;
}
}
User.prototype.saveUser = function(callback) { ... }
User.getUserById = function(id, callback) { ... }
module.exports = User;
Route(users.js):
var express = require('express');
var router = express.Router();
var User = require('../models/user');
router.route('/').post(function(req, res) {
new User(req.body, function(err, user) {
if(err) { ... }
user.saveUser(function(err, message) { ... }
});
})
router.route('/:id').get(function(req, res) {
User.getUserById(req.params.id, function(err, user) {
if(err) { ... }
res.json(user);
});
})

Resources