How to change default layout in express using handlebars?
Solution 1
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
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
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
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
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/',
...
![Alexander Kim](https://lh6.googleusercontent.com/-PoAJXbkM7UQ/AAAAAAAAAAI/AAAAAAAAAAs/Xi6TKFY8WWw/photo.jpg?sz=256)
Alexander Kim
Middle Frontend-engineer. Working with JS: Vue/Nativescript/Electron/Express || Koa.
Updated on July 05, 2022Comments
-
Alexander Kim almost 2 years
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');
- How can i change my default layout globally?
- What if i want to have 2 or 3 different global layouts?
-
Alexander Kim over 9 yearsThanks, but can't i do that globally?
-
Dan over 9 years@Heihachi I have updated the answer to include a global option.
-
Alexander Kim over 9 yearsthat's it! If i want few more global layouts i'll just duplicate a line with app.set(), right?
-
Dan over 9 yearsHow are you going to have multiple global layouts? How will your views know which global layout to use?
-
shriek over 9 yearsLate to the party but is it something that comes default in
express
or is this ahbs
thing? Because, I don't see any reference tolayout.hbs
either inapp.js
or inrouters/index.js
. -
shriek over 9 yearsNevermind, I found it. It's a
hbs
thing. If not specified it automatically sets the layout tolayout
. On line 115:-var layout_filename = path.join(view_dir, layout || 'layout');
-
Bharat over 8 years@TimothyStrimple just wondering, what if the data i want to send to the view includes the property called layout and i want to use res.render() to inherit a specific layout. multiple global layouts could be handy in a case where i want different assets and headers/footers/sidebars in different sections of the site. i could send JSON data to the layout view to do that, but then i wont be sending pure data to the view.
-
Tyguy7 over 7 yearsI had to google for a long time to find this answer. Thanks, wish it was more clear in the docs.
-
ibamboo over 7 yearsthanks, it works.but, i got another question, how did u know to set "view options", i cant find the reference in expressjs website.
-
chikitin over 5 yearsWhen I try this i get: ReferenceError: exphbs is not defined
-
venkat7668 over 5 yearsYou might miss this line in your code.. var exphbs = require('express-handlebars');
-
chikitin over 5 yearsYes. I thought installing it using express install ... would import it automatically. Thank you.
-
reggie over 5 yearsHorrible design choice to mix representational variables like that with the other variables...
-
0xAnon about 5 years
app.engine('hbs', hbs.engine); app.set('view engine', 'hbs');
on doing this in the exact same line , my page says: Error: ENOENT: no such file or directory, open '/home/ray/Desktop/phoneSkill/functions/views/layouts/main.handlebars' I wonder why it is happening ? But when i setvar hbs = exphbs.create({ defaultLayout: 'main.hbs', ...
in the exact same line it works and show me the pages. I wonder why this is happening ? shouldnot it be able to parse main.hbs automatically. ? -
skg about 4 years@Coderboi set
extname: 'hbs'
in config to modify default extension name. Example:var hbs = exphbs.create({ defaultLayout: 'main', extname: 'hbs', ...
-
Allen about 4 yearsthis is actually deprecated from express 4, it's just a handlebars thing.
-
fdrv over 2 yearsdoesnt work for me in 22