Source: the author

Templating engines are already a great invention — this is what I noticed again when I was working on a personal project with handlebars.js and Express recently.

Especially large websites with dynamic features and a lot of content can be very complicated to maintain if you just start writing the HTML code in a primitive way.

To solve this problem, you don’t have to use front-end frameworks to break everything down into reusable components.

Here are a few practical features of handlebars.js, which in combination with Express.js, are a lot of fun — and make developing websites a lot more comfortable.

What is a back-end templating engine?

If you already know, of course, you can skip this intro and jump directly to our setup installation.

Templating engines are mainly known from the front-end. Handlebars, for example, which is often associated with Mustache.js, can also be used in the front-end. With modern back-end platforms like Express.js, you can also enter the world of Node.js.

https://www.5kat.com/bat/a1/suba-Netherlands-Bosnia-cbn-00.html
https://www.5kat.com/bat/a1/suba-Netherlands-Bosnia-cbn-01.html
https://www.5kat.com/bat/a1/suba-Netherlands-Bosnia-cbn-02.html
https://www.5kat.com/bat/a1/suba-Netherlands-Bosnia-cbn-03.html
https://www.5kat.com/bat/a1/suba-Suomi-Bulgaria-cbn-00.html
https://www.5kat.com/bat/a1/suba-Suomi-Bulgaria-cbn-01.html
https://www.5kat.com/bat/a1/suba-Suomi-Bulgaria-cbn-02.html
https://www.5kat.com/bat/a1/suba-Suomi-Bulgaria-cbn-03.html
https://www.5kat.com/bat/a1/suba-Wales-v-Ireland-cbn-00.html
https://www.5kat.com/bat/a1/suba-Wales-v-Ireland-cbn-01.html
https://www.5kat.com/bat/a1/suba-Wales-v-Ireland-cbn-02.html
https://www.5kat.com/bat/a1/suba-Wales-v-Ireland-cbn-03.html
https://sv.tie.org/sv/go/suba-The-Masters-Golf-2020-cbn-00.html
https://sv.tie.org/sv/go/suba-The-Masters-Golf-2020-cbn-01.html
https://sv.tie.org/sv/go/suba-The-Masters-Golf-2020-cbn-02.html
https://sv.tie.org/sv/go/suba-The-Masters-Golf-2020-cbn-03.html
http://landrover.gi/land/go/suba-The-Masters-Golf-2020-cbn-00.html
http://landrover.gi/land/go/suba-The-Masters-Golf-2020-cbn-01.html
http://landrover.gi/land/go/suba-The-Masters-Golf-2020-cbn-02.html
http://landrover.gi/land/go/suba-The-Masters-Golf-2020-cbn-03.html
http://landrover.gi/land/lu/srs-q-v-d00.html
http://landrover.gi/land/lu/srs-q-v-d01.html
http://landrover.gi/land/lu/srs-q-v-d02.html
http://landrover.gi/land/lu/srs-q-v-d03.html
https://ayf.com/ayf/bk/srs-q-v-d00.html
https://ayf.com/ayf/bk/srs-q-v-d01.html
https://ayf.com/ayf/bk/srs-q-v-d02.html
https://ayf.com/ayf/bk/srs-q-v-d03.html
https://ayf.com/ayf/agu/suba-Netherlands-Bosnia-cbn-00.html
https://ayf.com/ayf/agu/suba-Netherlands-Bosnia-cbn-01.html
https://ayf.com/ayf/agu/suba-Netherlands-Bosnia-cbn-02.html
https://ayf.com/ayf/agu/suba-Netherlands-Bosnia-cbn-03.html
https://ayf.com/ayf/agu/suba-Suomi-Bulgaria-cbn-00.html
https://ayf.com/ayf/agu/suba-Suomi-Bulgaria-cbn-01.html
https://ayf.com/ayf/agu/suba-Suomi-Bulgaria-cbn-02.html
https://ayf.com/ayf/agu/suba-Suomi-Bulgaria-cbn-03.html
https://ayf.com/ayf/agu/suba-Wales-v-Ireland-cbn-00.html
https://ayf.com/ayf/agu/suba-Wales-v-Ireland-cbn-01.html
https://ayf.com/ayf/agu/suba-Wales-v-Ireland-cbn-02.html
https://ayf.com/ayf/agu/suba-Wales-v-Ireland-cbn-03.html
https://www.5kat.com/bat/a1/Neder-Bosnie-liv-Gua00.html
https://www.5kat.com/bat/a1/Neder-Bosnie-liv-Gua01.html
https://www.5kat.com/bat/a1/Neder-Bosnie-liv-Gua02.html
https://www.5kat.com/bat/a1/Neder-Bosnie-liv-Gua03.html
https://www.5kat.com/bat/a1/Neder-Bosnie-liv-Gua04.html
https://www.5kat.com/bat/a1/Neder-Bosnie-liv-Gua05.html
https://www.5kat.com/bat/a1/Wales-v-Ire-liv-Jeniva-Smn00.html
https://www.5kat.com/bat/a1/Wales-v-Ire-liv-Jeniva-Smn01.html
https://www.5kat.com/bat/a1/Wales-v-Ire-liv-Jeniva-Smn02.html
https://www.5kat.com/bat/a1/Wales-v-Ire-liv-Jeniva-Smn03.html
https://www.5kat.com/bat/a1/Wales-v-Ire-liv-Jeniva-Smn04.html
https://www.5kat.com/bat/a1/Wales-v-Ire-liv-Jeniva-Smn05.html
https://www.5kat.com/bat/a1/Wales-v-Ire-liv-Jeniva-Smn06.html
https://ayf.com/ayf/agu/Suomi-Bulgaria-xxx0.html
https://ayf.com/ayf/agu/Suomi-Bulgaria-xxx1.html
https://ayf.com/ayf/agu/Suomi-Bulgaria-xxx2.html
https://ayf.com/ayf/agu/Suomi-Bulgaria-xxx3.html
https://ayf.com/ayf/agu/Suomi-Bulgaria-xxx4.html
https://ayf.com/ayf/agu/Suomi-Bulgaria-xxx5.html
https://ayf.com/ayf/bk/Thiem-v-Tsitsipas-liv-Mara-de000.html
https://ayf.com/ayf/bk/Thiem-v-Tsitsipas-liv-Mara-de001.html
https://ayf.com/ayf/bk/Thiem-v-Tsitsipas-liv-Mara-de002.html
https://ayf.com/ayf/bk/Thiem-v-Tsitsipas-liv-Mara-de003.html
https://ayf.com/ayf/bk/Thiem-v-Tsitsipas-liv-Mara-de004.html
https://ayf.com/ayf/bk/Thiem-v-Tsitsipas-liv-Mara-de005.html
https://ayf.com/ayf/bk/Thiem-v-Tsitsipas-liv-Mara-de006.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-001.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-002.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-003.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-004.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-005.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-006.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-007.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-008.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-009.html
https://www.5kat.com/bat/a1/Wales-v-Ireland-liv-hd-tvc-uk-010.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-001.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-002.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-003.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-004.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-005.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-006.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-007.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-008.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-009.html
https://ayf.com/ayf/agu/Wales-v-Ireland-liv-hd-tvc-uk-010.html
https://ayf.com/ayf/bk/tt-Thiem-v-Tsitsipas-liv-tv-11.html
https://ayf.com/ayf/bk/tt-Thiem-v-Tsitsipas-liv-tv-12.html
https://ayf.com/ayf/bk/tt-Thiem-v-Tsitsipas-liv-tv-13.html
https://ayf.com/ayf/bk/tt-Thiem-v-Tsitsipas-liv-tv-14.html
http://landrover.gi/land/lu/tt-Thiem-v-Tsitsipas-liv-tv-11.html
http://landrover.gi/land/lu/tt-Thiem-v-Tsitsipas-liv-tv-12.html
http://landrover.gi/land/lu/tt-Thiem-v-Tsitsipas-liv-tv-13.html
http://landrover.gi/land/lu/tt-Thiem-v-Tsitsipas-liv-tv-14.html
https://ayf.com/ayf/agu/Wales-v-Ire-liv-Jeniva-Smn00.html
https://ayf.com/ayf/agu/Wales-v-Ire-liv-Jeniva-Smn01.html
https://ayf.com/ayf/agu/Wales-v-Ire-liv-Jeniva-Smn02.html
https://ayf.com/ayf/agu/Wales-v-Ire-liv-Jeniva-Smn03.html
https://ayf.com/ayf/agu/Wales-v-Ire-liv-Jeniva-Smn04.html
https://ayf.com/ayf/agu/Wales-v-Ire-liv-Jeniva-Smn05.html
https://ayf.com/ayf/agu/Wales-v-Ire-liv-Jeniva-Smn06.html
https://ayf.com/ayf/agu/Neder-Bosnie-liv-Gua00.html
https://ayf.com/ayf/agu/Neder-Bosnie-liv-Gua01.html
https://ayf.com/ayf/agu/Neder-Bosnie-liv-Gua02.html
https://ayf.com/ayf/agu/Neder-Bosnie-liv-Gua03.html
https://ayf.com/ayf/agu/Neder-Bosnie-liv-Gua04.html
https://ayf.com/ayf/agu/Neder-Bosnie-liv-Gua05.html
http://landrover.gi/land/lu/Thiem-v-Tsitsipas-liv-Mara-de000.html
http://landrover.gi/land/lu/Thiem-v-Tsitsipas-liv-Mara-de001.html
http://landrover.gi/land/lu/Thiem-v-Tsitsipas-liv-Mara-de002.html
http://landrover.gi/land/lu/Thiem-v-Tsitsipas-liv-Mara-de003.html
http://landrover.gi/land/lu/Thiem-v-Tsitsipas-liv-Mara-de004.html
http://landrover.gi/land/lu/Thiem-v-Tsitsipas-liv-Mara-de005.html
http://landrover.gi/land/lu/Thiem-v-Tsitsipas-liv-Mara-de006.html

Such an engine provides a template for the server, which has to be filled with concrete data for the finished application. When the user requests the server, the server will process the template and fill it out. The user does not notice anything; he only receives the finished web page.

Templating engines are therefore ideal for creating dynamic websites that do not have to ship tons of JS code to the user, so that the front-end can be used to make API calls, for example.

The computing load is put on the server. Furthermore, templating engines make developing a web application very easy and efficient. You can break the parts down into components as if you were using a front-end framework like React or Angular.

Reason enough to have a look at how we can make our life easier with handlebars.js.

Let’s install handlebars.js for Express.js

Create a fresh directory for our project first. Then install what is needed:

npm install -y npm install express express-handlebars

Then, create a /views directory.
This is the folder that express-handlebars will search for templates by default.

In the views folder, we create the layout folder, which is also used by express-handlebars by default. In this folder, we create the main.handlebars — it serves as a wrapper component.

Everything we write in there will be displayed under every route of our final web app — Therefore, it is ideal for embedding SEO tags and making file imports like CSS and JS.

Leave the main.handlebars like this: {{{body}}}

It means that we want to include here all the code that handlebars actually provides.

The final file-structure:

├── app.js
├── package-lock.json
└── views
├── index.handlebars
└── layouts
└── main.handlebars

app.js:

const express = require(‘express’);const exphbs = require(‘express-handlebars’);const app = express();app.engine(‘handlebars’, exphbs());app.set(‘view engine’, ‘handlebars’);app.get(‘/’, function (req, res) {
res.render(“index”);
});app.listen(8080);

Write something into the index.handlebars, start the server, and you should see a working project.

Let’s have a look at the first cool feature for making development easier.

Passing data and looping through it

Giving data from Express to handlebars is really easy.
The render function of express-handlebars gets an object as a second parameter, containing all data we want to provide.

let names = ["Max", "Tom", "Anna"]app.get(‘/’, function (req, res) {
res.render(“index”, {
students: names
});
});

index.handlebars:

<h1>Students:</h1>
<ul>
{{#each students}}
<li>{{this}}</li>
{{/each}}
</ul>

Result:

Basic stuff. But what about more complex objects?

Let’s make offer a few more details about our students:

let people = [
{name: “Max”, age: 21},
{name: “Tom”, age: 19},
{name: “Anna”, age: 25}
]

The changed index.handlebars:

<ul>
{{#each students}}
<li>{{this.name}}, {{this.age}}</li>
{{/each}}
</ul>

Result:

Conditions

In my current just-for-fun side project, I had the problem that I did not only want to display something under a true condition — also, if this condition is false, something else must be displayed at another place.

Yes, it sounds complicated, but actually it is not — here the real example:

Source: codingcheats.io

On the left and also on the right, under the JavaScript code, you see the same info-box — both boxes have the same CSS-styles, of course.

But on the left side, the box is still rounded at the top corners. Thanks to the conditionals in handlebars, I don’t need to create a single component for both, but can solve it in the following way:

  • If some source code is passed for display, it is automatically displayed above the infobox.
  • If no source code is passed, then the infobox is displayed alone.
  • How to solve the problem with rounded corners? Also, in the infobox component itself, it is checked if source code for displaying is provided.
  • In case no source code is passed, another CSS class is given to the infobox, which rounds the upper corners.

So I can use the same infobox component everywhere and, in special cases, handlebars automatically, with a check.
Of course, you need the use of conditionals; here is how to do this with handlebars:

Check condition for truth — if

Therefore we change the app.js a little bit:

let person = {
name: “Max”,
adult: false
}app.get(‘/’, function (req, res) {
res.render(“index”, {
person: person
});
});

index.handlebars:

{{#if person.adult}}
<p>person is an adult</p>
{{/if}}

And now, you should see nothing, since an adult is false. The problem is that in handlebars, there is no real else. What we need to use instead is unless, which is the inverse of if in this templating language:

{{#unless person.adult}}
<p>not an adult.</p>
{{/unless}}

Now you should see “not an adult.” on the website.

The difference between ‘{{ }}’ and ‘{{{ }}}’

This is a common mistake that many beginners of handlebars make. If we want to pass something with handlebars into our template, we can do this in two ways:

  • Providing content, which is then displayed between our HTML tags.
  • HTML structures, which are also rendered correctly.

Here is an example to show this:

let content = “<b>I am bold text</b>”app.get(‘/’, function (req, res) {
res.render(“index”, {
content: content
});
});

index.handlebars: {{content}}

This will lead to displaying as text:

3 curly brackets instead of just 2 will force handlebars to consider the content as valid HTML code:

{{{content}}} :

In my side project, I used this when I wanted to display italic or bold words for the code cheatsheets’ headlines.

Thank you for reading!

Join my mailing list to stay in touch with me

JavaScript In Plain English

Enjoyed this article? If so, get more similar content by subscribing to Decoded, our YouTube channel!

--

--