javascriptnode.jsvash

Node.js + Append to model before rendering a view


I am building a website using Node.js and Express. For my view engine, I'm using Vash.

In my app, I have a layout.vash file I'm using as the main layout for my app. It looks something like this:

layout.vash

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>@model.title</title>
  </head>
  <body>
    @html.block('content')
  </body>
</html>

I then have views that look something like this:

view.vash

@html.extend('layout', function(model){
    @html.block('content', function(model){
      <h1>Hello</h1>
    })
})

The view is referenced via Express with a route similar to this:

var router = require('express').Router();
router.get('/', function(req, res) {
    var viewModel = {
      title: 'Hello'
    };

    res.render('view', viewModel);
});

My viewModel will be unique to each view. However, there are some properties that are shared across all views. For example, for development purposes, I would like to know if the request is local or not. If I was using ASP.NET, I know I could say:

@if (Request.IsLocal) { ... }

However, I'm not sure how to do something similar with Node and Vash. My instincts tell me that I somehow need to append a property called isLocal to my model. However, I'm not sure if that's the correct idea, or if that's even possible.


Solution

  • I use the approach you are considering in my personal code.

    If the values you want to attach to your model are common across multiple routes, consider using a function to extend your model:

    function appendRouteData(model) {
        model.routes = {};
        model.routes.controller = "SomeController";
        model.routes.action = "index";
        model.routes.parameters = { foo: "bar" };
        return model;
    }
    
    ...
    
    viewModel = appendRouteData(viewModel);
    

    In response to your comments, there are multiple ways to include such a function in your users.js.

    Either expose the method as another module and require it, or, if we're going full crazy, inject a function that performs the same, but this requires some refactoring. I anticipate you doing only some of this insanity...

    // routes.js
    var UserRoutes = require('./users');
    function appendRouteData(controllerName) {
        // some crazy javascript here, might want to contemplate how this actually works first.
        return function (viewModel) {
            viewModel.routes.controller = controllerName;
            return viewModel;
        };
    }
    
    module.exports = {
        users: UserRoutes(appendRouteData('users'))
    };
    
    // users.js
    function UserRoutes(appendRouteData) {
        var router = require('express').Router();
        router.get('/users', function (req, res) {
            var viewModel = {};
            viewModel = appendRouterData(viewModel);
            res.render('users/index', viewModel);
        });
        return router;
    }
    module.exports = UserRoutes;