Search code examples
node.jsexpresshandlebars.jsexpress-handlebars

Express Handlebars Sections don't do anything


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?


Solution

  • 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 }