user3303012
user3303012

Reputation: 363

Handlebars with Express: different html head for different pages

I am using Handlebars in an Express Node.js app. My layout.html file includes a <head> section. How can I make the <head> section different for different pages? (So that I can, for example, reference a JavaScript file in only one page, and vary the <title> for each page.)

layout.html looks like this:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <script src='/public/ajsfile.js'></script>
    <link type='text/css' href="/public/style.css" rel="stylesheet">
  </head>
  <body>
    {{{body}}}
  </body>
</html>

(I am imagining varying the <head> content with something analogous to {{{body}}} in the above, but with {{{head}}}.)

Upvotes: 36

Views: 15963

Answers (4)

ViaTech
ViaTech

Reputation: 2813

I know this is an older question but I wanted to point out a clear alternative solution to what you are asking (I'm not entirely sure why nobody else spoke about it over the years). You actually had the answer you were looking for when you bring up placing things in {{{head}}} like you do for {{{body}}}, but I guess you needed help understanding how to make it work.

It seems possible that most of the answers on this page are geared towards Node "Sections" because you speak about the different sections of HTML you've included in your layout file that you want to change. The "Sections" everyone is speaking about in this thread seems to be a technique, although I may be mistaken, originating from Microsoft's Razor Template Engine. More info: https://mobile.codeguru.com/columns/dotnet/using-sections-and-partials-to-manage-razor-views.htm

Anyway Sections work for your question, and so could "Partials" theoretically (although it may not actually be the best option for this). More info on Partials: https://www.npmjs.com/package/express-partial

However, you simply asked for a way to alter the HTML tag content of your template layout in Handlebars, and assuming we are talking about HTML head tags, all you need to do is replace the content you have in your template layout HTML head tags with one of these (I use 3 brackets because it seems HTML would be included and you don't want it escaped):

<head> 
{{{headContent}}}
</head>

Then you just dynamically pass whatever data you want through the route you create in your app.js file to "get" the page like so (I am mostly taking the code @Fabricio already provided so I didn't have to rewrite this):

router.get('/', function (req, res) {
res.render( 'index', { headContent:'I DID IT!' });
});

Now when you load your page, "I DID IT!" will be where you expect it to show up.

Upvotes: 0

Younes
Younes

Reputation: 309

Maybe, you could use this implementation of the section helper: https://github.com/cyberxander90/express-handlebars-sections

You just need to install it and enable it:

yarn add express-handlebars-sections # or npm

const expressHandlebarsSections = require('express-handlebars-sections');

app.engine('handlebars', expressHandlebars({
    section: expressHandlebarsSections()
}));

Hope it helps.

Younes

Upvotes: 2

Fabricio
Fabricio

Reputation: 7925

You can make the follow:

layout.hbs

<head>
    <title>{{title}}</title>
    {{#each css}}
        <link rel="stylesheet" href="/css/{{this}}" />
    {{/each}}
</head>

app.js

router.get('/', function (req, res, next) {
    res.render('index', { title: 'MyApp', css: ['style.css', 'custom.css'] });
});

Result:

<head>
    <title>MyApp</title>
    <link rel="stylesheet" href="/css/style.css" />
    <link rel="stylesheet" href="/css/custom.css" />
</head>

Upvotes: 10

Ethan Brown
Ethan Brown

Reputation: 27282

This is a great question and, in my mind, a glaring weakness in Express's view model. Fortunately, there is a solution: use Handlebars block helpers. Here's the helper I use for this purpose:

helpers: {
    section: function(name, options){
        if(!this._sections) this._sections = {};
        this._sections[name] = options.fn(this);
        return null;
    }
}

Then, in your layout, you can do the following:

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

And in your view:

{{#section 'head'}}
    <!-- stuff that goes in head...example: -->
    <meta name="robots" content="noindex">
{{/section}}

<h1>Body Blah Blah</h1>
<p>This goes in page body.</p>

Upvotes: 66

Related Questions