admin管理员组

文章数量:1293915

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 mon 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>

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 mon 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>
Share edited Mar 4, 2015 at 19:59 Ninethousand asked Mar 4, 2015 at 19:25 NinethousandNinethousand 5352 gold badges7 silver badges16 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 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:

{{> mon_header}}

to embed the mon_header template inside of the current template. That mon_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.


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

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

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.

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.pile(
    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>

本文标签: javascriptTemplate inheritance with NodejsHandlebars and ExpressStack Overflow