Express Handlebars Sections don't do anything

769 views Asked by At

I am currently trying to implement sections into my website using express handlebars. My code looks like this:

index.js

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

const app = express();
app.engine("handlebars", expressHandlebars({
    defaultLayout: "main",
    helpers: {
        section: (name, options) => {
            if (!this._sections) {
                this._sections = {};
            }
            this._sections[name] = options.fn(this);
            return null;
        }
    }
 }));
app.set("view engine", "handlebars");
app.use(express.static("public"));

app.get("/", (req, res) => {
    res.render("home", { title: "Home" });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Listening on port ${PORT}`);
});

views/layouts/main.handlebars

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>{{{ title }}}</title>

        {{{_sections.head}}}
    </head>
    <body>

        {{{ body }}}

    </body>
</html>

views/home.handlebars

{{#section "head"}}
<style>
    h1 {
        color: "red";
    }
</style>
{{/section}}

<h1>test</h1>

Expected Result:

It correctly displays the h1 tag with the text "test". However, the heading should be red due to the {{#section "head"}}, but it is black.

I have installed express and expressHandlebars correctly.

What could be wrong?

2

There are 2 answers

0
romellem On BEST ANSWER

The answer above doesn't actually address your issue.

The real problem is: Don't use arrow functions when defining a Handlebars Helper.

Because of that, this within the helper isn't set correctly so rendering it our via options.fn(this) doesn't work.

So the real fix should be:

app.engine(
    'handlebars',
    expressHandlebars({
        defaultLayout: 'main',
        helpers: {
            //  Importantly, define the helper as a regular `function`, _not_ an arrow-function.
            section(name, options) {
                if (!this._sections) {
                    this._sections = {};
                }
                this._sections[name] = options.fn(this);
                return null;
            },
        },
    })
);

See the bellow SO post for more information on this:

Also, you have a typo on your CSS:

h1 { color: "red" }

Is not correct; The color datatype doesn't include quotes. So the correct CSS should be

h1 { color: red }
0
Mahdad On

It works if you declare style in head of your source html.

views/home.handlebars should read:

<head>
    <style>
        h1 {
            color: red;
            border: solid 1px green;
        }
    </style>
</head>

<h1>test</h1>