Jrapa86
Jrapa86

Reputation: 127

Express-Handlebars Multiple Layouts

I am currently trying to use handlebars where I can reference multiple themes/layouts easily. My intention is for example, when rendering a new page I can choose which layout. Each layout links to a different set of JS/CSS files. For Example: I would be able to do:

router.get('/bootstrap', function (req, res){ 
   res.render('general', {layout: bootstrap, data: variables});   
});
                     ---or --
router.get('/semantic', function(req,res){
   res.render('general', {layout: semantic, data: variables});

I thought that this could be easily achieved by simply creating (bootstrap/semantic.hbs) templates like this in my /views/layouts directory and typing

res.render('general', {layout: 'bootstrap', data: variables});

However this doesnt seem to work

// bootstrap_layout.hbs

<html>
<head>
<link ref....to bootstrap css>
<body>
   {{{body}}}

<script src...to jquery>
<script src...to bootstrap js>
{{> Footer }}
</body>
<html>

My app.js file looks like this:

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

var app = express();
var hbs = exphbs.create({
   layoutsDir: /views/layouts });

// Register `hbs.engine` with the Express app.
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');

The problem is when I try to do this, I cannot seem to load the layout/template when calling it in {layout: bootstrap} or {layout: semantic}. I run into errors where the layout cannot be found, vs other ENOENT errors. I also tried changing this:

Remove: var hbs = exphbs.create({
   layoutsDir: /views/layouts });
--------------------------------
Remove: hbs. engine, and replace with exphbs: 

app.engine('handlebars', exphbs({layoutDir: __dirname+'/views/layouts'}));
app.set('view engine', 'handlebars');

I have had no luck in figuring out why I am running into so much difficulty calling a new layout. Does anyone have any advice on where I may be going wrong or if I am missing something essential?

Thanks!

Upvotes: 1

Views: 2558

Answers (3)

76484
76484

Reputation: 9003

One suggestion I have is that the extension on your layout files is incompatible with your configuration.

You have specified that your layouts have paths like views/layouts/semantic.hbs. However, I believe that express-handlebars expects the extension ".handlebars" by default. (You can override this in your exphbs.create, like exphbs.create({ extname: '.hbs' }))

In summary, please try using the ".handlebars" extension for your view files. The resultant paths would look like:

./views/general.handlebars
./views/layouts/bootstrap.handlebars
./views/layouts/semantic.handlebars

A basic example of the express code is:

const express = require("express");
const exphbs = require("express-handlebars");
const path = require("path");

const app = express();
const port = 3000;

const hbs = exphbs.create({
  layoutsDir: path.join(__dirname, "/views/layouts"),
});

app.engine("handlebars", hbs.engine);
app.set("view engine", "handlebars");

const variables = {
  foo: "bar",
};

app.get("/bootstrap", function (req, res) {
  res.render("general", { layout: "bootstrap", data: variables });
});

app.get("/semantic", function (req, res) {
  res.render("general", { layout: "semantic", data: variables });
});

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

Upvotes: 0

Darius Vanderbeek
Darius Vanderbeek

Reputation: 1

If you store your [bootstrap/semantic] layouts under views/layouts, it will work. So,

app.set('view engine', 'handlebars');
app.set('views', './views');

and then

res.render('general', {layout: 'bootstrap', data: variables});

Upvotes: 0

C&#225;ssio Lacerda
C&#225;ssio Lacerda

Reputation: 1634

Using single quote in the name of layout that you choose when you call render method:

res.render('general', {layout: 'bootstrap', data: variables});

Upvotes: 0

Related Questions