I have two files in helpers folder, one is EventHelper.js and UserEvent.js,
helpers/EventHelper.js
function EventHelper() {
this.onEventCreated = function(err, e) {...}
this.isExisting = function(id) {...}
}
module.exports = new EventHelper();
helpers/UserEvent.js
var EventHelper1 = require('./EventHelper')
var EventHelper2 = require('./EventHelper.js')
function UserEvent() {
this.fireEvent = function(req, res) {
var EventHelper3 = require('./EventHelper');
...
EventHelper1.onEventCreated(err, e);
EventHelper2.onEventCreated(err, e);
EventHepler3.onEventCreated(err, e);
}
};
module.exports = new UserEvent();
controllers/EventController.js
var EventHelper = require('../helpers/EventHelper')
var UserEvent = require('../helpers/UserEvent');
var EventController = {
fireEvent: function(req, res) {
if(EventHelper.isExisting(req.params.id)) UserEvent.fireEvent(req, res)
...
}
}
EventHelper1 and EventHelper2 in UserEvent.js are always empty(having {}), where as EventHelper3 is being initialised properly and able to refer object's methods properly. I have referred this EventHelper.js in different controllers folder(EventController.js) globally and it was getting populated properly. I am not sure if I am missing something here
You're missing some semicolons:
function EventHelper() {
this.onEventCreated = function(err, e) {...}
this.isExisting = function(id) {...}
}**;**
module.exports = new EventHelper();
For instance after adding this one, I got the EventHelper within your Controller, which I haven't gotten before.
Furthermore (I guess it's just and typo here and not in your actual code, since then you couldn't get an instance for it), it's:
EventHelper3.onEventCreated(err,e);
and not `
EventHepler3.onEventCreated(err,e);
So to sum up, the following is now working for me:
// EventHelper.js
function EventHelper() {
this.onEventCreated = function(err, e) {
console.log('testCreate');
};
this.isExisting = function(id) {
console.log('testExists' + id);
return true;
};
};
module.exports = new EventHelper();
// UserEvent.js
var EventHelper1 = require('./EventHelper.js');
var EventHelper2 = require('./EventHelper.js');
function UserEvent() {
this.fireEvent = function(req, res) {
console.log(req + res);
var EventHelper3 = require('./EventHelper');
EventHelper1.onEventCreated(req, res);
EventHelper2.onEventCreated(req, res);
EventHelper3.onEventCreated(req, res);
};
};
module.exports = new UserEvent();
// EventController.js
var EventHelper = require('../helpers/EventHelper.js');
var UserEvent = require('../helpers/UserEvent.js');
var EventController = {
fireEvent: function(req, res) {
if(EventHelper.isExisting(1)) UserEvent.fireEvent(req, res);
};
}
EventController.fireEvent("1","2");
Withe the following output:
testExists1
12
testCreate
testCreate
testCreate
I hope that I could help you!
Related
I have 3 different files called: app.js, ServerManager.js and Users.js.
To start everything, I run app.js which runs my ServerManager.
Running ServerManager in App.js:
var ServerManager = require('./modules/ServerManager.js');
var serverManager = new ServerManager({
app: app,
path: __dirname
});
Then serverManager is called and I can do stuff in there, then I'm trying to send stuff to Users.js from ServerManager but it seems like it doesn't work.
ServerManager.js
var config = require('../config.js');
var express = require('express');
var colors = require('colors');
var DatabaseManager = require('../modules/DatabaseManager.js');
var RouteManager = require('../modules/RouteManager.js');
var Users = require('../data/users.js');
module.exports = function(options){
return new ServerManager(options);
}
var ServerManager = function (options) {
var self = this;
this.app = options.app;
this.options = options;
this.dbManager = new DatabaseManager();
this.dbManager.use();
this.RoutesManager = new RouteManager(this.app);
this.RoutesManager.use();
this.usersManager = new Users(this);
}
ServerManager.prototype.getDatabase = function () {
return this.dbManager();
}
Users.js - Marked in code what it can't find.
module.exports = function (ServerManager) {
return new Users(ServerManager);
};
var Users = function (ServerManager) {
var self = this;
this.serverManager = ServerManager;
};
Users.prototype.createUser = function (username, email, password) {
this.serverManager.getDatabase(); <--- Can't find getDatabase()
};
I think that you should change your Users.js code to:
// This is the Users object
// and this function is its constructor
// that can create users instances
var Users = function (ServerManager) {
var self = this; this.serverManager = ServerManager;
};
// We define a method for the user object
Users.prototype.createUser = function (username, email, password) {
this.serverManager.getDatabase();
};
// We export the user object
module.exports = Users;
Now the then you do
var Users = require('../data/users.js');
you get the User object.
And so, you can do new Users(...).
The same thing has to be done for the ServerManager.
If you want to use your code as it is, you don't have to use the new keyword on the imported object.
I have an Mongo, Express, Angular, Node application. I am trying to pass a variable that is a response of a method in 1 file to a different method in a different file.
So during a series of user actions it triggers a method exports.test inside the test.controller.js file
looks like this:
exports.test = function(req, res) {
var query = 'crazy query'
var params = { key:value }
var cb = function(err,stuff) {
});
res.json(stuff);
var testOutput = res.json(stuff);
return testOutput;
}
sendToServer(query,params,cb);
}
Notice how I have set testOutput equal to the response from the server. And I have returned testOutput, from the method.
Now I was curious, I have another controller actions.controller.js. And inside of this file I have a method called exports.actions
looks like this:
exports.actions = function(req, res, testOutput) {
console.log(testOutput);
var query = 'crazy query'
var params = { key:value }
var cb = function(err,stuff) {
});
res.json(stuff);
}
sendToServer(query,params,cb);
}
I am trying to expose var testOutput from test.controller.js to actions.controller.js, so I can pass testOutput as an argument into the exports.actions method. Is this possible?
You cannot directly expose any variable to other controllers. Communication between controllers can happen via services.
Define a service to update and save the value of testOutput:
angular.module('myApp',[])
.factory('myService',function(){
var init = {};
init.update = function(newVal) {
init.testOutput = newVal;
};
return init;
}]);
Your controllers:
angular.module('myApp')
.controller('Ctrl1',['myService',function(myService){
exports.test = function(req, res) {
var query = 'crazy query'
var params = { key:value }
var cb = function(err,stuff) {
});
res.json(stuff);
var testOutput = res.json(stuff);
myService.update(testOutput);
}
sendToServer(query,params,cb);
}
}]);
angular.module('myApp')
.controller('Ctrl2',['myService',function(myService){
exports.actions = function(req, res) {
console.log(mapService.testOutput); //use the variable as u like
var query = 'crazy query'
var params = { key:value }
var cb = function(err,stuff) {
});
res.json(stuff);
}
sendToServer(query,params,cb);
}
}]);
I've had no trouble testing my own route handlers but in this case I want to test express's static handler. I can't for the life of me figure out why it's hanging. Clearly there's some callback I'm missing or some event I need to emit.
I tried to make the smallest example I could.
var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');
function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;
this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);
this.on('finish', function() {
console.log("finished response");
callback();
});
};
util.inherits(MockResponse, stream.Writable);
MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
function createRequest(req) {
var emitter = new events.EventEmitter();
req.on = emitter.on.bind(emitter);
req.once = emitter.once.bind(emitter);
req.addListener = emitter.addListener.bind(emitter);
req.emit = emitter.emit.bind(emitter);
return req;
};
describe('test', function() {
var app;
before(function() {
app = express();
app.use(express.static(__dirname));
});
it('gets test.js', function(done) {
var req = createRequest({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);
function responseDone() {
console.log("done");
done();
}
});
});
Setup,
mkdir foo
cd foo
mkdir test
cat > test/test.js # copy and paste code above
^D
npm install express
npm install mocha
node node_modules/mocha/bin/mocha --recursive
it just times out.
What am I missing?
I also tried making the request a Readable stream. No change
var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');
function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;
this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);
this.on('finish', function() {
console.log("finished response");
callback();
});
};
util.inherits(MockResponse, stream.Writable);
MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
function MockMessage(req) {
stream.Readable.call(this);
var self = this;
Object.keys(req).forEach(function(key) {
self[key] = req[key];
});
}
util.inherits(MockMessage, stream.Readable);
MockMessage.prototype._read = function() {
this.push(null);
};
describe('test', function() {
var app;
before(function() {
app = express();
app.use(express.static(__dirname));
});
it('gets test.js', function(done) {
var req = new MockMessage({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);
function responseDone() {
console.log("done");
done();
}
});
});
I've still been digging. Look inside static-server I see it creates a Readable stream by calling fs.createReadStream. It does effectively
var s = fs.createReadStream(filename);
s.pipe(res);
So trying that myself works just fine
it('test stream', function(done) {
var s = fs.createReadStream(__dirname + "/test.js");
var res = new MockResponse(responseDone);
s.pipe(res);
function responseDone() {
console.log("done");
done();
}
});
I thought maybe it's something about express waiting for the input stream to finish but that doesn't seem to be it either. If I consume the mock input stream with the response it works just fine
it('test msg->res', function(done) {
var req = new MockMessage({});
var res = new MockResponse(responseDone);
req.pipe(res);
function responseDone() {
console.log("done");
done();
}
});
Any insight what I might be missing would be helpful
Note: while suggestions for 3rd party mocking libraries are appreciated I'm still really looking to understand what I'm missing to do it myself. Even if I eventually switch to some library I still want to know why this isn't working.
I found two issues that prevent the finish callback from being executed.
serve-static uses send module which is used to create file readstream from the path and pipe it to res object. But that module uses on-finished module which checks if finished attribute is set to false in response object, otherwise it destroys the file readstream. So filestream never gets a chance to emit data event.
express initialization overwrites the response object prototype. So the default stream methods like end() method is overwritten by http response prototype:
exports.init = function(app){
return function expressInit(req, res, next){
...
res.__proto__ = app.response;
..
};
};
To prevent this, I added another middleware right before static middleware to reset it back to MockResponse prototype:
app.use(function(req, res, next){
res.__proto__ = MockResponse.prototype; //change it back to MockResponse prototype
next();
});
Here are the changes made to make it work with MockResponse:
...
function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely
//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);
...
};
...
describe('test', function() {
var app;
before(function() {
app = express();
//another middleware to reset the res object
app.use(function(req, res, next){
res.__proto__ = MockResponse.prototype;
next();
});
app.use(express.static(__dirname));
});
...
});
EDIT:
As #gman pointed out, it is possible to use direct property instead of prototype method. In that case the extra middleware to overwrite prototype isn't necessary:
function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely
//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);
...
//using direct property for _write, write, end - since all these are changed when prototype is changed
this._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
this.write = stream.Writable.prototype.write;
this.end = stream.Writable.prototype.end;
};
It appears my answer is not complete. For some reason the app works only if the file is not found. First thing to debug is do the following in your shell (or cmd):
export DEBUG=express:router,send
then run the test, you'll get more info.
Meanwhile I am still looking into this, for now, ignore my answer below.
----------- ignore this till I verify that it does work -----------
It seems like express static does not favor the absolute path you give it (__dirname).
Try:
app.use(express.static('.'));
and it will work. Note that your current dir for the mocha runner is 'test/'
I have to admit this is quite a mistery. I tried 'fulling' it by doing:
app.use(express.static(__dirname + '/../test')
but still it didn't work. Even specifying a full path did not solve this. Strange.
I am using Nodejs Express. I currently have a script that produces an array of objects from Google API. I need to take that JSON data and use it in my templates. How can I call the function in my script from my route file?
This is my script file:
var Spreadsheet = require('edit-google-spreadsheet');
Spreadsheet.load({
debug: true,
spreadsheetId: '1eWmSV4Eq-se4gZSvBfW-J-lEOLwNopEfMavZByJ-qD8',
worksheetId: 'owrromd',
// 1. Username and Password
username: 'user',
password: 'pass',
}, function sheetReady(err, spreadsheet) {
//use speadsheet!
spreadsheet.receive(function(err, rows, info) {
if (err) throw err;
var announcementArray = [];
//console.log(rows);
for (x in rows) {
var eachObject = rows[x]
var side = eachObject['1'];
//console.log(side);
var type = eachObject['2'];
//console.log(type);
var announcement = eachObject['3'];
//console.log(announcement);
var announcementItem = {};
announcementItem.side = side;
announcementItem.type = type;
announcementItem.announcement = announcement;
announcementArray.push(announcementItem);
}
announcementArray.shift();
console.log(announcementArray);
});
});
This is my route js file:
module.exports=function(app){
app.get('/', function(req,res){
res.render('index', {title:"Home page", description:"The is the description"});
});
}
Change the content of the script file, let's call it loadSheet.js
var Spreadsheet = require('edit-google-spreadsheet');
function loadSheet() {
Spreadsheet.load({
debug: true,
spreadsheetId: '1eWmSV4Eq-se4gZSvBfW-J-lEOLwNopEfMavZByJ-qD8',
worksheetId: 'owrromd',
// 1. Username and Password
username: 'user',
password: 'pass',
}, function sheetReady(err, spreadsheet) {
//use speadsheet!
spreadsheet.receive(function(err, rows, info) {
if (err) throw err;
var announcementArray = [];
//console.log(rows);
for (x in rows) {
var eachObject = rows[x]
var side = eachObject['1'];
//console.log(side);
var type = eachObject['2'];
//console.log(type);
var announcement = eachObject['3'];
//console.log(announcement);
var announcementItem = {};
announcementItem.side = side;
announcementItem.type = type;
announcementItem.announcement = announcement;
announcementArray.push(announcementItem);
}
announcementArray.shift();
console.log(announcementArray);
});
});
}
//Export it to module
exports.loadSheet = loadSheet;
Then in the route js:
var ls = require('./loadSheet.js'); //Load the module, get the name of the script file
app.get('/', function(req,res){
res.render('index', {title:"Home page", description:"The is the description"});
ls.loadSheet();
});
So you'd adapt the module the other response created. But you are going to need to give a callback to loadSheet. I am cutting out the main body of that function for clarity.
var Spreadsheet = require('edit-google-spreadsheet');
function loadSheet(theCallback) { //take a callback here.
Spreadsheet.load({...yourdata...}, function sheetReady(...) {
// create your announcementArray
// then call the callback
theCallBack(undefined,announcementArray);
});
});
}
//Export it to module
exports.loadSheet = loadSheet;
Then, from your routes, you can get it like so:
var ls = require('./loadsheet.js'); // assumes in same dir as routes
app.get('/', function(req,res){
ls.loadSheet(function(err,result){
res.render('myTemplate',result);
});
});
I am going to assume you can take care of getting the result data into your template. You can look in the index template to see how it pulls in the data. I don't know whether you are using Jade or EJS.
Note, this is all sort of hackish but addresses your functional question. Let me know if you need a little further direction.
I have a basic Node JS server which is designed to be used as an API, I've created a log and database module and I've started adding other modules to deal with different request types.
I'm using Express.js and node-mysql
When I visit /v1/group I get the following error -
TypeError: Cannot read property 'database' of undefined
at Group.getAll (C:\code\javascript\node\api\api\v1\groups.js:12:23)
at callbacks (C:\code\javascript\node\api\node_modules\express\lib\router\index.js:161:37) ...
So I guess after recieving a request and calling group.getAll() that this is undefined but I don't understand why, is there a way to set this or have I structured my application all wrong?
sever.js
"use strict";
var Express = require('express');
var Log = require('./database/log');
var Database = require('./database/database');
var dbConfig = require('./dbconfig.json');
var Group = require('./api/v1/groups');
//Init express
var app = new Express();
//Init log and database
var log = new Log();
var database = new Database(dbConfig, log);
var initCallback = function() {
//Init routes
var group = new Group(database, log);
//Group routes
app.get('/v1/group', group.getAll);
app.get('/v1/group/:id', group.getByID);
app.listen(3000);
log.logMessage("INFO", "Listening on port 3000");
};
//Test database connection
database.getConnection(function(err, connection) {
if (err) {
log.logMessage("FATAL", "Error connecting to database, check database is running and the dbconfig.json file is present and correct.");
process.exit(1);
}
connection.end();
initCallback();
});
database.js
"use strict";
var mysql = require('mysql');
var Database = function(dbConfig, log) {
this.connected = false;
this.log = log;
this.log.logMessage("INFO", "Connecting to database with: Host - " + dbConfig.dbhost + ", Database port - " + dbConfig.dbport + ", Database name - " + dbConfig.dbname + ", User " + dbConfig.dbuser + ", Password length - " + dbConfig.dbpass.length);
this.pool = mysql.createPool({
host : dbConfig.dbhost,
user : dbConfig.dbuser,
port: dbConfig.dbport,
password : dbConfig.dbpass,
database: dbConfig.dbname
});
};
Database.prototype.getConnection = function() {
var args = arguments;
return this.pool.getConnection.apply(this.pool, arguments);
};
module.exports = Database;
groups.js
"use strict";
var Group = function(database, log) {
this.database = database;
this.log = log;
};
Group.prototype.getAll = function(req, res) {
console.log(this); // --> undefined
var query = 'SELECT * FROM invgroups WHERE published = 1';
this.database.getConnection(function(err, connection) { // --> error line
if (err) { res.send(500, "Database error"); }
connection.query(query, function(err, results) {
if (err) { res.send(500, "Database error"); }
res.send(results);
});
connection.end();
});
};
Group.prototype.getByID = function(req, res) {
console.log(this);
res.send({name: "Group Item 1"});
};
module.exports = Group;
You need to properly bind the function.
app.get('/v1/group', group.getAll);
only passes the getAll function as a handler, but the function itself has no concept of this. this is decided based on the context that is bound, or based on how the function is called. This blog post is useful for understanding how function context works.
app.get('/v1/group', group.getAll.bind(group));