18

I'm developing a site with Node.js + Express and using as view engine Hogan.js.

This is my file app.js:

/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');

var app = express();

app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'hjs');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.cookieParser('your secret here'));
  app.use(express.session());
  app.use(app.router);
  app.use(require('less-middleware')({ src: __dirname + '/public' }));
  app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
  app.use(express.errorHandler());
});

app.get('/', routes.index);
app.get('/about', routes.about);
app.get('/users', user.list);

http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});

The file /routes/index.js is:

/*
 * GET pages.
 */

exports.index = function(req, res){
  res.render(
    'index',
    {
      title: 'Home Page',
      author: 'Bruce Wayne'
    }
  );
};

exports.about = function(req, res){
  res.render(
    'about',
    {
      title: 'About Page',
      author: 'Bruce Wayne'
    }
  );
};

In /views folder, there are:

|- part.hjs

|- index.hjs

|- cv.hjs

The file part.hjs is:

<h3>Hello {{ author }}</h3>

The file index.hjs is:

<h1>Title: {{ title }} </h1>
{{> part }}
Welcome to Gotham City.

And the file about.hjs is:

<h1>Title: {{ title }}</h1>
{{> part }}
I'm not Joker.

I've two questions:

  1. How can I use properly the partials in my pages? (this code doesn't work)
  2. Can I use the same "title" for two or more pages without repeat the values assignment in file /routes/index.js?

Best regards, Vi.

6 Answers6

25

I've found a solution for the first question.

First of all, I removed hjs:

npm remove hjs

Then, I installed the package hogan-express:

npm install hogan-express

Furthermore, I edited app.js:

/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');

var app = express();

app.engine('html', require('hogan-express'));
app.enable('view cache');

app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.set('views', __dirname + '/views');
  app.set('view engine', 'html');
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.cookieParser('your secret here'));
  app.use(express.session());
  app.use(app.router);
  app.use(require('less-middleware')({ src: __dirname + '/public' }));
  app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
  app.use(express.errorHandler());
});

app.get('/', routes.index);
app.get('/users', user.list);

http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});

And routes/index.js:

exports.index = function(req, res) {
  res.locals = {
    title: 'Title',
  };
  return res.render(
    'index',
    {
      partials:
      {
        part: 'part',
      }
    }
  );
};

Now, in /views there are index.html, part.html. The file part.html contains:

<h1>{{ title }}</h1>

The file index.html contains:

{{> part}}
Hello world!

So, It works fine.

6

At least in Express 4+, partials just work out of the box. You can use express-generator (from npm) with --hogan or -H option.

After doing that, you need to add partials to the render method:

router.get('/', function(req, res, next) {
  res.render('index', 
        { 
            title: 'My Site',
            partials: {header: 'header'} 
        });
});

Then, in your template use {{ > xxx }}

<body>
  {{> header }}
  <h1>{{ title }}</h1>

  <p>Welcome to {{ title }}</p>
</body>

NOTE: this has header.hjs in views

bryanmac
  • 38,941
  • 11
  • 91
  • 99
4

To use partials with express+hogan, just do the following:

app.get('/yourRoute', function(req, res){  
   res.render('yourPartial', function(err,html){
       var partialHTML = html;
       res.render('yourMainView', { myPartial: partialHTML }, function(err,html){
          res.send(html);   
       });     
   });
}

And now, yourMainView.html:

<p>Something Something Something</p>
{{{partialHTML}}}
<p>Bla Bla Bla</p>

Notice the triple '{' instead of double as you usually do! That telling hogan (mustache) to parse this as HTML rather then a string!

That's it.

Oren Yakobi
  • 279
  • 1
  • 4
  • 14
  • Do you know how to assign the to a Javascript variable ? something like: But with the security of html escape caracters, etc.. ???? – cmarrero01 Feb 18 '17 at 00:04
3

As for your partials question, if you use consolidate.js you can simply do:

res.render('index', {
  partials: {
    part  : 'path/to/part'
  }
});
Nathan Walker
  • 182
  • 1
  • 7
ydaniv
  • 1,289
  • 11
  • 18
2

This is a problem. Partial support is difficult to come by in Express 3.

Your best bet is: https://github.com/visionmedia/consolidate.js npm install consolidate

These patches take different approaches to adding partials for Hogan:

Unfortunately, the engine doesn't have a hook for filesystem based partials natively, so I think people are confused about how and where partials should be implemented. I ended up with LinkedIn's Dust.js implementation, since partial support was already there. Master actually has even better support, plus I submitted a patch yesterday for relative paths.

Josh

Josh
  • 12,602
  • 2
  • 41
  • 47
  • Thank you so much. I could find a solution for partials using hogan-express package. There are differences with consolidate? Which is better? –  Oct 08 '12 at 19:43
  • 1
    Consolidate may have actual support for partials. In the solution you listed below, you have to forward declare all your partials and pass them in in the options hash. Thats somewhat inconvenient, but not unworkable. In other languages you can just say {>partial/} and it will pull in the partial off the filesystem directly. – Josh Oct 08 '12 at 22:39
2

I would use mmm instead of hjs.

https://github.com/techhead/mmm

Disclaimer: I wrote the package.

Just replace all occurrences of hjs with mmm and partials will start working. There is a lot more information and an example at the link above.

As for your other question, if you want to share properties across multiple views, you have a couple of options.

When you call res.render(name, options), the options will actually be merged onto res.locals and app.locals before being passed to the rendering engine. Therefore to set an app-wide property, you can simply assign it to app.locals.

app.locals.title = "Default Title"; // Sets the default title for the application

This concept really applies to just about any Express 3 View Engine.

However, for mmm specifically, please see the section under Presentation Logic for more ways to bind values to a template or set of templates.

Jonathan Hawkes
  • 953
  • 2
  • 12
  • 24
  • I'm having similar problems, and I don't want to follow the next solution and explicitly pass a partials variable to my templates. I'm going to try mmm now. Hope this works. I already tried hulk-hogan, only to realise it didn't work with express 3.x – Naman Goel Jan 13 '13 at 23:10
  • Bad suggestion. What if the OP has a ton of work done using hjs already. Changing a template engine to solve such a simple problem is massive overkill – Paul Allsopp Dec 02 '17 at 20:31