var s_bookingController = require('s/controllers);
app.get('/dashboard/:page/:param', s_bookingController.index)
app.get('/dashboard/show/:id', s_bookingController.show);
Controllers:
exports.index = function(req, res, next) {
var page = parseInt(req.param("id"));
data = {};
data.page = page;
data.nextPage = page + 1;
data.prevPage = page - 1;
MyModel.find().sort('brand').skip((page-1)*11).limit(11).exec(function(err, result) {
res.render('index', {
data: data,
booking: result,
});
});
};
And
exports.show = function(req, res, next) {
var id = req.param("id");
res.send(id);
};
I'm using this controllers, but there is something wrong with the code of the exports.index, because it's stuck in the code.
If I change the routes to:
app.get('/dashboard/:page', s_bookingController.index)
(Note that I'm take off the second parameter that I was passing)
the show will work, but if I use the second parameter, the show will not run, it will be stuck in the index page.
Why is this? I was wondering if I need use the next();.
Expanding my comment:
You should have the following order of the routes:
app.get('/dashboard/show/:id', s_bookingController.show);
app.get('/dashboard/:page/:param', s_bookingController.index);
Express routing requires that a more specific route should be placed above the more general one.
The /dashboard/show/:id is more specific in this case as /dashboard/:page/:param covers it, so that /dashboard/show is handled by it. When the route is handled next routes are not executed.
Related
I am trying to add paging using express-paginate module. But i am getting limit parameter in url like this: http://example.com:3010/feeds?page=2&limit=10.
But i don't want to use limit in url. How i can remove limit from url?
Below is my pug file code.
if paginate.hasPreviousPages || paginate.hasNextPages(pageCount)
.navigation.well-sm#pagination
ul.pager
if paginate.hasPreviousPages
li.previous
a(href=paginate.href(true)).prev
i.fa.fa-arrow-circle-left
| Previous
if pages
each page in pages
a.btn.btn-default(href=page.url)= page.number
if paginate.hasNextPages(pageCount)
li.next
a(href=paginate.href()).next
| Next
i.fa.fa-arrow-circle-right`
I think you can add this by creating a simple middleware function, e.g.
const app = express();
const DEFAULT_PAGE_COUNT = 10;
// Intercept all calls and add a default page count.
app.use(function(req, res, next) {
if (!("limit" in req.query)) {
req.query.limit = DEFAULT_PAGE_COUNT;
}
next();
});
And actually, I believe the module supplies this middleware function, e.g.
// keep this before all routes that will use pagination
// paginate.middleware(limit, maxLimit)
const paginate = require('express-paginate');
app.use(paginate.middleware(10, 50));
I am making a project with node, express, and jade. I want to access content through:
/Page/foo/bar
and
/Page?Foo=foo&Bar=bar
I want the top to be an alias for the bottom.
This is the solution I have now:
server.js
// some stuff
app.get('/Page/:Foo/:Bar',function(req,res){
res.render('Page.jade', {Foo: req.params.Foo, Bar: req.params.Bar});
});
app.get('/Page',function(req,res){
res.render('Page.jade', {Foo: req.query.Foo, Bar: req.query.Bar});
});
// more stuff
Page.jade
doctype html
html
head
script var foo = "!{Foo}"; bar = "!{Bar}";
script(src="/Page.js")
// stuff
Page.js
// stuff with foo and bar, such as:
console.log(foo);
console.log(bar);
The thing I don't like about this solution is that it forces me to handle the params and query separately with express (which is almost duplicate code, but not quite close enough to reduce it), pass it to jade, which stores it in a variable for the sole purpose of having a linked javascript file use those variables.
Normally just using query strings I would only have to touch it in Page.js. Is there a way to set up express to effectively interpret the first URL as a query string, like the second URL, so the jade file doesn't have to touch the variables?
Option 1: If you just want to reduce code redundancy, maybe you could save your controllers in an external file, so you will end up with something like this:
controllers/fooBarController.js:
exports.fooBarQueryOrParams = function(req, res) {
res.render('Page.jade', {
Foo: req.params.Foo || req.query.Foo,
Bar: req.params.Bar || req.query.Bar
});
}
You could also add a default value with another || operator if undefined is not valid four you.
server.js:
var fooBarController = require('controllers/fooBarController');
app.get('/Page/:Foo/:Bar', fooBarController.fooBarQueryOrParams);
app.get('/Page', fooBarController.fooBarQueryOrParams);
Option 2: Same thing, but using res.locals, so now there's no need to pass any object to Page.js, all your views will see res.locals properties just by its names, in this case Foo and Bar (not res.locals.Foo and res.locals.Bar).
controllers/fooBarController.js:
exports.fooBarQueryOrParams = function(req, res) {
res.locals.Foo = req.params.Foo || req.query.Foo;
res.locals.Bar = req.params.Bar || req.query.Bar;
res.render('Page.jade');
}
server.js:
var fooBarController = require('controllers/fooBarController');
app.get('/Page/:Foo/:Bar', fooBarController.fooBarQueryOrParams);
app.get('/Page', fooBarController.fooBarQueryOrParams);
Option 3: Always expose everything thought res.locals:
controllers/fooBarController.js:
exports.fooBarQueryOrParams = function(req, res) {
res.render('Page.jade');
}
server.js:
var fooBarController = require('controllers/fooBarController');
app.use(function(req, res, next) {
for (var key in req.params) res.locals[key] = req.params[key];
for (var key in req.query) res.locals[key] = req.query[key];
next();
});
app.get('/Page/:Foo/:Bar', fooBarController.fooBarQueryOrParams);
app.get('/Page', fooBarController.fooBarQueryOrParams);
I would go for the first option as I suppose you don't really need to use Foo and Bar in all your views, so there's no point in using res.locals to expose them to all your views instead of just to the ones that really need them.
You could just set the object properties yourself and continue to the next route etc
app.use('/Page/:Foo/:Bar',function(req, res, next){
for (var key in req.params) {
req.query[key] = req.params[key];
}
next();
});
I have two routes: /news and /news-paginate (I know it is a not good URL but it doesn't matter atm). In the news route, I load 5 records from the database and render a populated view. In the /news-paginate route, I load other 5 records based on the page number and size sent from the client; this route responds with a JSON object.
news route
router.get('/news', function (req, res) {
...
connection.query(queries['news_list'], [language, +pageSize, +offset], function (err, rows) {
res.render('news', {news: rows});
});
});
news-paginate route
router.get('/news-paginate', function (req, res) {
var language = 'RU';
var pageSize = req.query.pageSize;
var pageNumber = req.query.pageNumber;
var offset = (pageNumber - 1) * pageSize;
connection.query(queries['news_list'], [language, +pageSize, +offset], function (err, rows) {
res.json(rows);
});
});
I am concerned about my architecture. Is my approach correct? I have two routes with the same functionality and different responses. Should I somehow combine these two routes into one?
Hmm, I usually have a single route, in your case /news which can receive 2 optional params: pageSize, pageNumber for your pagination purposes. If those params don't exists than you will offer the first 5 records. If those params are present than you will start providing the other 5 records and based on the calculated offset.
router.get('/news/:pageSize?/:pageNumber?', function (req, res) {
var language = 'RU';
var pageSize = req.params.pageSize || 5;
var pageNumber = req.params.pageNumber || 1;
var offset = (pageNumber - 1) * pageSize; // If no params are provided than the offset should be 0
connection.query(queries['news_list'], [language, +pageSize, +offset], function (err, rows) {
res.json(rows);
});
});
I am not familiar with optional params in express routes but I hope you get the main idea behind the approach.
You can do ajax requests to load the extra records after the first 5 records are listed.
I hope this shined a light on the approach.
I am trying to write a module that creates generic handlers for express routes
e.g.
//create a new route handler with some config
//every routeHanlder method needs to be able to access this config
var handler = new routeHandler({config: "value"});
//handle a get route ("Example 1")
app.get('route', handler.read)
//handle a get route with params ("Example 2")
app.get('route.:id', function(req, res){
handler.read(req,res,{query: {_id: req.params.id}});
});
I am having trouble making "example 1" work...
app.get('route', handler.read)
...as I loose the value of 'this' inside handler.read
I understand why the value of 'this' is different, but I can't figure out how to make it work, or another way to get the desired results without using 'this'.
Here is a plunker link
To summarise I am trying to find a way to make my routeHandler objects (see plunker above, and code paste below) work when used as the callback of an express route (see "example 1" above).
var routeHandler = function(config){
if (!(this instanceof(routeHandler))) {
return new routeHandler(config);
}
config = config || {};
if(config.configData){
this.configData = config.configData;
}
};
routeHandler.prototype = {
read: function(req, res, options){
//The problem: accessing configData without using this
console.log("inside callback", this, this.configData);
options = options || {};
}
};
Edit: I would like the ability to create multiple instances of the route handler with different config data e.g.
var handlerOne = new RouteHandler("configDataOne");
var handlerTwo = new RouteHandler("configDataTwo");
app.get('/firstRoute', handlerOne.read);
app.get('/secondRoute', handlerTwo.read);
You can save routeHandler's configData in express object "app" like below:
app.set("routeHandlerConfigData", "identifier or whatever value you want to store");
then make your routeHandler a simple middleware
var routeHandler = function(req, res, next){
var configData = req.app.get("routeHandlerConfigData");
//Do whatever you want
};
I was inspired by a great comment form yerforkferchips who suggested adding my routerHandler functions inside the constructor like this
this.read = (function read(...) { ... }).bind(this);
Which lets me do exactly what I wanted in my question
app.get('route', handler.read);
BUT i realised that I could use closures in my prototype functions which would sort my 'this' problem and that I would also be able to take in configuration data without having to wrap handler.read in a separate callback function on app.get
RouteHandler.prototype = {
read: function(config){
return function(req, res){
//I have access to req, res and config
}
}
}
so now I can do this
app.get('route', handler.read("configData"));
instead of this
app.get('route', function(req, res){
hander.read(req, res, "configData");
});
What I am trying to do:
Using middleware function I want to store user data from session in to locals so I can use it later in my views without store those data in every method / controller.
Instead of (in every method / controller):
function(req, res){
data.user = req.session.user;
res.render('someView', data);
}
and in View (template):
<div>
#model.user.username
</div>
i want to define middleware like this:
if (req.session.user) {
var now = new Date().getTime();
var data = req.session.user;
var timeout = data.loggedIn + config.auth.timeout;
if (timeout < now) {
req.session.user = null;
reg.flash('errors', {
param: 'default',
msg: 'Your session is expired...'
});
return res.redirect('/login');
}
res.locals.user = sesData;
}
return next();
and in view display my data from res.locals. And there is my BIG questionmark... is it possible ?
I could find any information how to display data from res.locals in vash views.
Am i missing something, is my solution plausible ?
UPDATE
Finally i found solution. Displaying app.locals in VASH views is quite simple :-)
View:
<div>
#model._locals.user.username
</div>
would do what i need :-)
I hope someone will find it useful.