简体   繁体   中英

How should I populate data in an express.js page layout

I have a fairly standard requirement for a web app where most of the pages will be rendered with a single layout (I'm using handlebars but the same would apply to Jade or anything else).

The layout uses quite a bit of data from the database and may require several lookups. How should I structure the code so that the data used by the layout does not have to be retrieved in each controller for each page/route? In many web frameworks there is a simple way to intercept routes by pattern and have that interceptor make the required lookups, decorating the model generated by the controller that they wrap.

It feels like there should be some way to do that with the right definition of middlewares, but I can't figure it out.

Looking for something that does what my pseudo-code below shows:

router.get('/', ctrlPublic.index);
router.get('/index.html', ctrlPublic.index);
router.get('/find-us.html', ctrlPublic.findUs);

// apply same interceptor to all (/*)
router.intercept('/*', ctrlDecorator.main);

// ctrlPublic...
index: function(req, res) {
    // get data for index page, then render index.hbs
},
findUs: function(req, res) {
    // get data for find-us page, then render find-us.hbs
}

// ctrlDecorator...
main: function(req, res) {
    // lookup data needed by main layout - this gets automatically 
    // added to the model used by the page ctrlPublic handlers
}

I would ideally like interceptors target the controllers by pattern matching rather than declaration in the router.get() call, and for them to be additive so that more than one could apply to a certain set of controllers.

Is there a module that helps with this, or just a general "best practice" way to achieve it?

If i understand your question right you need a global middleware to fetch the data and pass it to the respective controller so you dont load the same layout data on the controller right?

In that case create a global middleware

 app.use(function(req, res, next){
    var excludeMiddleware = ['login', 'test', 'test2'];
    //simple example for bypassing the middleware
    for(var i = 0; i < excludeMiddleware.length; i++){
       if(excludeMiddleware[i] === req.path) { return next(); }
    }                

    someAsyncFnFromDb.then(function(dataFromDb){
       //req.layoutData = dataFromDb;          
       res.locals.layoutData  = dataFromDb;
       return next();
    }).catch(function(err){
       return next(); // or throw new Error(err)
    });
});

and in your controller assign the data to the render function if you use req.layoutData , example

res.render('myView', { layoutData: req.layoutData });

or leave your controller as is if you use res.locals.layoutData and the layoutData will be available on your view.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM