How to change default layout in express using handlebars?

node.jsExpresshandlebars.js

node.js Problem Overview


I am using Express 4.9.0 and express-generator.

Created boilerplate with a following command:

express --hbs projectname

Builtin handlebars is using views/layout.hbs by default as a master page. But i cannot see any settings in my app.js to change that behaviour.

piece of code from my app.js:

// view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'hbs');

  1. How can i change my default layout globally?
  2. What if i want to have 2 or 3 different global layouts?

node.js Solutions


Solution 1 - node.js

You can specify what layout you want to use as part of the render call. If you create a new layout called other.hbs, you can then do something like:

res.render('view', { title: 'my other page', layout: 'other' });

To override this for the entire application, you can use:

app.set('view options', { layout: 'other' });

Solution 2 - node.js

From the handlebars readme:

> There are two ways to set a default layout: configuring the view engine's defaultLayout property, or setting Express locals app.locals.layout.

> The layout into which a view should be rendered can be overridden per-request by assigning a different value to the layout request local. The following will render the "home" view with no layout:

> app.get('/', function (req, res, next) { > res.render('home', {layout: false}); > });

In case you want to set the default layout just for a specific subroute, you might wanna use the following in the top section of your route:

router.all('/*', function (req, res, next) {
	req.app.locals.layout = 'admin'; // set your layout here
	next(); // pass control to the next handler
    });

You can also set the default layout on initialization:

// Create `ExpressHandlebars` instance with a default layout.
var hbs = exphbs.create({
    defaultLayout: 'main',
    helpers      : helpers,

	// Uses multiple partials dirs, templates in "shared/templates/" are shared
	// with the client-side of the app (see below).
	partialsDir: [
		'shared/templates/',
		'views/partials/'
		]
	});

// Register `hbs` as our view engine using its bound `engine()` function.
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');

Solution 3 - node.js

This should work now..

npm install express-handlebars

.
├── app.js
└── views
    ├── home.handlebars
    └── layouts
        └── main.handlebars
 
2 directories, 3 files

app.js

var express = require('express');
var exphbs  = require('express-handlebars');
 
var app = express();
 
app.engine('handlebars', exphbs({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
 
app.get('/', function (req, res) {
    res.render('home');
});
 
app.listen(3000);

views/layouts/main.handlebars:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Example App</title>
</head>
<body>
 
    {{{body}}}
 
</body>
</html>

Solution 4 - node.js

I hope you are using express-handlebars. This instructions are for express-handlebars. For hbs, procedures are little different.

Step-1: Require handlebars

const exphbs = require('express-handlebars');

step-2: Register handlebars template engine. while registering, you can configure

for changing layout directory

const layoutPath = path.join(__dirname, './templates/layouts'); //you can build your desired path
app.engine('handlebars', exphbs({ layoutsDir: layoutPath }));

other available options along with layoutsDir are

interface ExphbsOptions {
    handlebars?: any;
    extname?: string;
    layoutsDir?: string;
    partialsDir?: any;
    defaultLayout?: string;
    helpers?: any;
    compilerOptions?: any;
}

step-3: If you want to change views directory

const viewPath = path.join(__dirname, './templates/views');
app.set('views', viewPath);

step-4: For some template, If you don't wish to give layout, you have to specify as layout: false . Otherwise app will crash. You can configure as follow, if you need.

app.get('/', (req, res, next) => {
    res.render('shop', { title: 'My Shop', layout: false })
});

For more info about express-handlebars

Solution 5 - node.js

If you're using the 'express-handlebars' module, then the following should work:

// ...
app.set("views", __dirname );

exphbs.ExpressHandlebars.prototype.layoutsDir = 'path/to/directory/';
app.engine('handlebars', exphbs({defaultView: 'name-of-template'}));

// ...

I came to this by digging around in the module's source, it turns out that this line...

// express-handlebars/lib/express-handlebars.js (line 55 in v1.2.2)
ExpressHandlebars.prototype.layoutsDir  = 'views/layouts/';

...is what gives the default behaviour of always looking in '{{whatever you specified}}/views/layouts/'

So essentially - if, perhaps, you have a different dir structure in mind or have some other reason to override it, you can by using the line in my example. Just be sure that you do this before you instantiate exphbs.

If you're using some other module (I'm not sure which are out there) it's likely that they have some similar setting that can be overridden with a bit of jiggery-pokery (just run a 'find' on the file contents for 'views/layouts/'.

note that I am leaving 'app.set("views", __dirname );' as is so that I keep templates anywhere in my server directory and render them like so:

res.render("moduleName/templateName");

After updating to v2.0.1 The above won't work, instead you can pass the default directory in as an argument as below:

var hbs = exphbs.create({
  layoutsDir: 'app/server/',
  ...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexander KimView Question on Stackoverflow
Solution 1 - node.jsTimothy StrimpleView Answer on Stackoverflow
Solution 2 - node.jsFlaudreView Answer on Stackoverflow
Solution 3 - node.jsvenkat7668View Answer on Stackoverflow
Solution 4 - node.jsAnand RajaView Answer on Stackoverflow
Solution 5 - node.jsSpenView Answer on Stackoverflow