I am recently learning express.js. The code below is copied from the router lib of express.js.
var proto = module.exports = function(options) {
options = options || {};
function router(req, res, next) {
router.handle(req, res, next);
}
// mixin Router class functions
router.__proto__ = proto;
router.params = {};
router._params = [];
router.caseSensitive = options.caseSensitive;
router.strict = options.strict;
router.stack = [];
return router;
};
My question is what is returned if I call
var Router = require('./router');
var _router = new Router(...);
What is _router? Is it the function router(req, res, next)? If yes, can I call _router(req, res, next);?
If I am wrong, could someone please explain what does the code do?
If yes, why don't they just do it like:
var proto = module.exports = function(options) {
options = options || {};
var router = {};
// mixin Router class functions
router.__proto__ = proto;
router.params = {};
router._params = [];
router.caseSensitive = options.caseSensitive;
router.strict = options.strict;
router.stack = [];
return router;
};
For your first question:
var Router = require('./router');
var _router = new Router(...);
var Router is a object of created by the function router(req, res, next), and your var router is a new object of Router. In javascript almost everything is an object. You can read more here.
If they use your aproach they won't have a constructor. And they use the constructor to do router.handle(req, res, next); I don't know why they need the handle, you can study more the code or ask the developers. But you probably can use the var router new Router(req,res,next); if you know what the params do.
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 wanted to see the implementation of express.Router.get.
I looked at the express source on git, starting with the project's index.js.
The index has module.exports = require('./lib/express'). That file has var Router = require('./router'). That location is a directory, so I checked the index.js file in that directory. Sure enough it has:
var proto = module.exports = function(options) {
var opts = options || {};
function router(req, res, next) {
router.handle(req, res, next);
}
// mixin Router class functions
setPrototypeOf(router, proto)
router.params = {};
router._params = [];
router.caseSensitive = opts.caseSensitive;
router.mergeParams = opts.mergeParams;
router.strict = opts.strict;
router.stack = [];
return router;
};
That's the code that returns the router function. However, there is no .get function defined anywhere. Where is the actual function defined?
Note: I'm asking about the get function you would use like:
router.get('/', ...).
Browsing Express v4.15.2 I found the following in express/lib/application.js (line 468)
/**
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
*/
methods.forEach(function(method){
app[method] = function(path){
if (method === 'get' && arguments.length === 1) {
// app.get(setting)
return this.set(path);
}
this.lazyrouter();
var route = this._router.route(path);
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});
where this._router is coming from express/lib/router/index.js
From there depending on what you are looking for you have either:
express/lib/router/layer.js::match (line 110) that checks if this route matches path, if so populate .params
express/lib/router/route.js::dispatch (line 98) that dispatchs req, res to that route
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);
}
}]);
In the past, you could have done something like this:
app.get(['/', '/dashboard'], (req, res, next) => { ... });
in order to have multiple routes using the same route handler.
Several Stack Overflow answers indicate that this behavior is deprecated and should not be used anymore.
Aside from an ugly regex or a semi-hack like putting the function into a variable and passing it to 2 distinct app.get() calls, is there an elegant alternative to just passing an array as the first argument?
Do something like this:
var express = require('express');
var app = express();
var originalExpressGet = app.get;
app.get = (function() {
var expressApp = app;
function turnToArray(args){
var array = [];
for(var i = 0; i < args.length; i++){
array.push(args[i]);
}
return array;
}
return function(routes, callback) {
var args = turnToArray(arguments);
if(args.length <= 1){
return originalExpressGet.apply(app, arguments);
}
if(!Array.isArray(routes)){
routes = [routes];
}
args.shift();
routes.forEach(function(route){
originalExpressGet.apply(app, [route].concat(args));
});
}
return app;
}());
That way you are still using express's app.get, but it allows you to use [] for multiple routes. For example, this works:
app.get(['/', '/same'], function(req, res){
res.send(true);
});
And so does this:
app.get('/another route', function(req, res){
res.send(true);
});
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!