Template inheritance with Node.js, Handlebars and Express
Asked Answered
C

5

7

I'm just getting started with Node.js, so I'm building very simple applications in order to practice the basics. I was trying to get some Django-like template inheritance working, but I'm at a bit of a loss on how to do it.

I understand that the library "express-handlebars" includes the concept of layouts, and I thought that might be the best way to go about it, but at first glance I don't know if it allows more than one step of inheritance, or using it for replacing different blocks (I saw one general layout where the other templates are inserted in place of the {{{body}}} tag, although there may very well be more tricks to it).

So, my question: how would one implement a multi-layered template inheritance (also, with children inserting content into different separate blocks, instead of a single one)? I'm using Node.js, Express and handlebars, but if it's not possible with the latter two I don't mind trying out other frameworks or templating languages.

Thanks!

Edit:

A pseudo-coded example of what I mean:

First, we could have a common outer template:

<html>
    <head></head>
    <body>
        <h1> Main Title </h1>
        <h2> {{section name block}} </h2>
        <h3> {{subsection name block}} </h3>
        {{content block}}
    </body>
</html>

then another one under it (middle template), substituting some of the outer one's blocks (and potentially adding other ones):

{{inheriting from outer template}}
{{section name block}} Section Three {{/block}}

and finally an inner one, which would be the one to call from the javascript code:

{{inheriting from middle template}}
{{subsection name block}} Subsection Two {{/block}}
{{content block}}
    <p>This is the content of Section Three, Subsection Two.</p>
{{/block}}

The result when processing the inner template would be:

<html>
    <head></head>
    <body>
        <h1> Main Title </h1>
        <h2> Section Three </h2>
        <h3> Subsection Two </h3>
        <p>This is the content of Section Three, Subsection Two.</p>
    </body>
</html>
Centistere answered 4/3, 2015 at 19:25 Comment(0)
B
3

It not 100% clear what you're asking for with the term "inheritance" for templates, but handlebars templates can include templates which can include other templates which can include templates so you can nest as deep as you want.

For example, I just use the syntax:

{{> common_header}}

to embed the common_header template inside of the current template. That common_header could itself embed other templates in it and so on.


You can also use layouts (discussed here) which allows you to have a master-like template which different content can be rendered into.


FYI, there's a discussion of a Django-like template inheritance using Handlebars here and here and a layouts extension for Handlebars here and more discussion of using layouts in Handlebars here.


Barrett answered 4/3, 2015 at 19:32 Comment(1)
Thanks! I added to the main post an example of the kind of inheritance I was thinking about. I will check those other discussions.Centistere
E
2

Swig seems to have that functionality

http://paularmstrong.github.io/swig/docs/#inheritance

Haven't personally used it but looks like the same inheritance syntax as PHP's Twig, so should be OK

Eh answered 4/3, 2015 at 19:37 Comment(3)
I though the question was asking about how to do inheritance in Handlebars, not how to find some other template system.Barrett
Thanks! I will try to find a way with Handlebars, but if I can't I will give Swig a try.Centistere
maybe try this method: gist.github.com/mmcgahan/9fa045d98c7c122f1c0b seems even more elegant than traditional single inheritance (basically you define content for named blocks THEN include "inherited" templates)Eh
W
1

Anyone landing on this question may want to know about this : Swig is no longer supported as their github says

That said, Nunjucks looks like the only alternative out there for extensible templating in Javascript. The syntax is very similar to the one of Twig (PHP)

I hope this helps

Wattage answered 16/11, 2017 at 11:1 Comment(0)
C
0

This can be achieved using the npm package handlebar-layouts.

You can have a parent layout main.hbs:

<html>
    ...
    <body>
        {{#block "header"}}
            <h1>Hello World</h1>
        {{/block}}
 
        {{#block "main"}}
            <p>Lorem ipsum.</p>
        {{/block}}
 
        {{#block "footer"}}
            <p>&copy; 1999</p>
        {{/block}}
    </body>
</html>

And then your child layouts can be child.hbs:

{{#extend "layout"}}
 
    {{#content "header"}}
        <h1>Goodnight Moon</h1>
    {{/content}}
 
    {{#content "main" mode="append"}}
        <p>Dolor sit amet.</p>
    {{/content}}
 
    {{#content "footer" mode="prepend"}}
        <p>MIT License</p>
    {{/content}}
 
{{/extend}}

See more usage in the documentation above.

Cheyney answered 29/8, 2023 at 22:8 Comment(0)
S
0

This can now be achived using the inline partials of native Handlebars:

/* build.js */
const Handlebars = require('handlebars');
const fs = require('node:fs');
const {resolve, extname} = require('node:path');

const templateDir = resolve(__dirname, 'templates');

// register partials for templates/*.hbs
for (const file of fs.readdirSync(templateDir)) {
  const ext = extname(file);
  if (ext.toLowerCase() !== '.hbs') {
    continue;
  }
  Handlebars.registerPartial(
    file,
    fs.readFileSync(resolve(templateDir, file), 'utf-8')
  );
}

const tpl = Handlebars.compile(
    fs.readFileSync(resolve(templateDir, 'top.hbs'), 'utf-8')
);
const content = tpl();

console.log(content);
<!-- base.hbs -->
<html>
    <head></head>
    <body>
        <h1> Main Title </h1>
        <h2> {{#> middle}}{{/middle}} </h2>
        <h3> {{#> subsection}}{{/subsection}} </h3>
        {{#> content}}{{/content}}
    </body>
</html>
<!-- middle.hbs -->
{{#> base.hbs}}
{{#*inline "middle"~}} Section Three {{~/inline}}
{{/base.hbs}}
<!-- top.hbs -->
{{#> middle.hbs}}
{{#*inline "subsection"~}} Subsection Two {{~/inline}}
{{#*inline "content"~}}
    <p>This is the content of Section Three, Subsection Two.</p>
{{~/inline}}
{{/middle.hbs}}

Run with Node.js:

$ npm install handlebars
$ node build.js
<html>
    <head></head>
    <body>
        <h1> Main Title </h1>
        <h2> Section Three </h2>
        <h3> Subsection Two </h3>
        <p>This is the content of Section Three, Subsection Two.</p>
    </body>
</html>
Selfdevotion answered 13/8, 2024 at 16:53 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.