50

I am trying to make a simple HelloWorld project with Node.js|Express using Handlebars.js as a server template engine.

The problem is that I couldn't find any examples of using such chain, especially with multiple view.

For example I would like to define header view:

<header>
  <span>Hello: {{username}}</span>
</header>

And use it in every page with other views.

Maybe I am thinking about this views in a wrong way, I thought that view is kind of control that I can reuse on any page inside any other view.

I appreciate any link to the tutorial or (much better) open source project that I can lear from.

fmsf
  • 36,317
  • 49
  • 147
  • 195
Artem Yarulin
  • 509
  • 1
  • 7
  • 12

5 Answers5

80

I know this had been asked a long time ago, but no one has shown an answer in this post. So I will do so here. To ensure everyone is on the same page, I will be verbose in my answer. I apologize in advance if it seems overly simplistic.

In your server.js file (or app.js, wherever you defined handlebars as your view engine). Depending on what you are using as your npm package, such as hbs or express-handlebars etc. it may look different, but similar to this. Note: I'm using express-handlebars in this example.

file: server.js

...
var express     = require( 'express'),
    hbs         = require( 'express-handlebars' ),
    app         = express();
...

app.engine( 'hbs', hbs( { 
  extname: 'hbs', 
  defaultLayout: 'main', 
  layoutsDir: __dirname + '/views/layouts/',
  partialsDir: __dirname + '/views/partials/'
} ) );

app.set( 'view engine', 'hbs' );

...

and your file structure should look something like this:

| /views/   
|--- /layouts/
|----- main.hbs
|--- /partials/
|----- header.hbs
|----- footer.hbs
|----- ... etc.
|--- index.hbs
| server.js

And your main.hbs file should look like this:

file: main.hbs

...
{{> header }}
...
<span> various other stuff </span>
...
{{> footer }}

To denote a partial you use this syntax: {{> partialsNames }}.

Tristan Isfeld
  • 1,448
  • 12
  • 7
  • 1
    This is so helpful. Now, when I go to render a view, which includes multiple partials, how do I send it? suppose I have `var router=express.Router()` and `router.get("/", function(req, res){ ...some data function... res.render('index', {some: data}, [partials])`. What gets passed as the option here? How do I tell `render()` to post data to the proper partial? – wlh Mar 23 '17 at 21:46
  • I had the same question, and this provided the context around this good answer: https://hackersandslackers.com/handlebars-templates-expressjs/ – RockMeetHardplace Feb 10 '20 at 13:24
39

Using https://www.npmjs.org/package/hbs | https://github.com/donpark/hbs

Let's assume you have:

+ views
  - index.hbs
  + partials
    - footer.hbs

You need to register which folder contains your partials:

hbs.registerPartials(__dirname + '/views/partials');

The partials will have the exact name that the file has. You can also register specific names for your partials by using:

hbs.registerPartial('myFooter', fs.readFileSync(__dirname + '/views/partials/footer.hbs', 'utf8'));

Then you access it like this:

First example: {{> footer }} 
Second example: {{> myFooter }}

Full example here: https://github.com/donpark/hbs/tree/master/examples/partial

fmsf
  • 36,317
  • 49
  • 147
  • 195
4

I'm currently using ericf's implementation of "handlebars-express", and find it to be excellent:

https://github.com/ericf/express3-handlebars

The key thing to remember is that on express, as opposed to the within the browser, handlebars gets activated during the view render phase. The client code will end up being just plain HTML, as if you'd used mustache within a PHP context.

1

You need to use partials.

See https://github.com/donpark/hbs/tree/master/examples/partial for a good example of using partials.

Here's another example http://blog.teamtreehouse.com/handlebars-js-part-2-partials-and-helpers

Troy
  • 68
  • 6
0

If your current directory is something like this then,

| /public/   
| /views/ 
|--- /layouts/
|----- main.hbs 
|--- /partials/ 
|----- header.hbs 
|----- footer.hbs 
|----- sidebar.hbs 
|--- index.hbs 
| app.js 

Then the structure of app.js will be

const express = require('express');
const app = express();
const port = 3001;
const path = require('path');
const handlebars = require('express-handlebars');

app.use(express.static(path.join(__dirname, 'public'))); 

app.set('view engine', '.hbs');
app.engine('.hbs', handlebars({
    layoutsDir: __dirname + '/public/views/layouts',
    defaultLayout: 'main',
    extname: 'hbs', 
    //for partial directory
    partialsDir : __dirname+'/public/views/partials',
}));

app.set('views', path.join(__dirname, '/public/views'));

app.get('/', (req, res) => {  
    res.render('index');
});

app.listen(port, () => console.log(`App listening to port ${port}`));

Set the main.hbs as follows

const express = require('express');
{{> header}}
{{> sidebar}}
<p>Your Content(static) or you can use {{{body}}} </p>
{{> footer}}