Most useful express handlebar tricks

Blog


author small image Siva Kishore G
Posted : 30 Dec 2021
Modified : 23 Mar 2023
Intermediate Developers

Express Handlebars as templating engine

This tutorial is for beginner - intermediate node js developers who chose handlebars as their templating engine. I chose this as it is easily readable and over the course of time, I've learned some techniques that will help you to leanify (I don't even know if that's a word) your project structure.

npm install express-handlebars --save
Just to recap on how to install

1. Only load the resources you need

There are times where your website pages need different CSS / JS resources but not all. Traditionally, you would include all resources in your head / footer of the layout page. This will cause the webpage to load unnecessary bloat and use-up the browser memory. Nowadays, browsers can handle a lot of memory and are sufficient to load and execute quite a few JS, css and image files. Even so, it's your duty as a quality developer to minimize these overheads as much as possible.

Now you would ask, the JS / CSS are loading from the cache and where is the overhead ? Ok, let's say you are going to a math class and will you carry all the books required for your entire course?I REST MY CASE !

Below is your regular html layout file. Notice how I implemented the {{#if}} statements to import the only required JS / CSS. In the node js code I've passed "pageCSS" & "isProduction" to get the desired result.

<!DOCTYPE html>
<html lang="en">
  <head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<meta http-equiv = "X-UA-Compatible" content="IE=edge">
        <link rel="icon" href="/static_files/images/favicon.png"/>
        <meta name='robots' content='index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1' />
        <link rel="canonical" href="https://yourwebsite.com{{currentPage}}" />
        <link rel="preconnect" href="https://fonts.googleapis.com">
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <link href="https://fonts.googleapis.com/css2?family=Cabin&family=Quicksand:wght@400;700&display=swap" rel="stylesheet">
      	<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="/static_files/css/common.css">

        {{#if pageCSS}}
      	<link rel="stylesheet" type="text/css" href="/static_files/css/{{pageCSS}}.css">
        {{/if}}
        <title>{{title}}</title>
      	<meta name="description" content= "{{meta}}">

        {{#if isProduction}}
        <!-- Global site tag (gtag.js) - Google Analytics -->
        {{/if}}
app.get('/', (req, res) => {
  res.render("home", {
    pageJS: 'home',
    title: "My Awesome title",
    meta: "my awesome meta title",
    pageCSS: "home",
    isProduction: true
  })
})

2. Helpers help!

Helpers, the very name says it all.. It's your best friend in need.. truly. There are countless situations where I stored the timestamp in my database in unix string format and I have to display it in the local time string on the browser. With helpers, you can do this in one line of code. Really!

<div>
  {{timeformat 1640811742676}}
  {{timeformat 2021-12-30T21:02:44.022Z}}
</div>
timeformat: function(val){
  return val ? (new Date(val)).toLocaleDateString() : ""
}

You can create your custom HTML templates. This will make your code much easier to maintain and less code to be written. To render the html code, you must use three curly braces instead of two. Did you know you can label the variables while using helper functions? Lets see it in action

<div>
 {{{myLayout heading="Super blog" para="This is a para about my super blog"}}}
</div>
myLayout: function(val){
    var hash = val.hash
    return `
    <div>
      <h2 class="my-3">${hash.heading}</h2>
      <p>${hash.para}</p>
    </div>
    `

3. Access parent params

Time to time, you would want to access the parent object key in each loop. You can do this simply by adding "../" before the object key. In the below example, we are passing two params parentItem and items. When we are in items loop, we accessed the parentItem with "../parentItem"

app.get('/items',(req,res)=>{
  res.render('items-page',{
    parentItem: 'comments',
    items: [{
      "postId": 1,
      "id": 1,
      "name": "id labore ex et quam laborum",
      "email": "Eliseo@gardner.biz",
      "body": "laudantium enim quasi est quidem magnam voluptate ipsam eos\ntempora quo necessitatibus\ndolor quam autem quasi\nreiciendis et nam sapiente accusantium"
    },
    {
      "postId": 1,
      "id": 2,
      "name": "quo vero reiciendis velit similique earum",
      "email": "Jayne_Kuhic@sydney.com",
      "body": "est natus enim nihil est dolore omnis voluptatem numquam\net omnis occaecati quod ullam at\nvoluptatem error expedita pariatur\nnihil sint nostrum voluptatem reiciendis et"
    },
    {
      "postId": 1,
      "id": 3,
      "name": "odio adipisci rerum aut animi",
      "email": "Nikita@garfield.biz",
      "body": "quia molestiae reprehenderit quasi aspernatur\naut expedita occaecati aliquam eveniet laudantium\nomnis quibusdam delectus saepe quia accusamus maiores nam est\ncum et ducimus et vero voluptates excepturi deleniti ratione"
    }]
  })
})
{{#each items}}
  <div>
    <h3>{{../parentItem }}</h3>
    Name : {{this.name}}<br />
    Email : {{this.email}}<br />
  </div>
{{/each}}

4. Highlight the active page

Typically, the header navbar and footer columns remain the same for the entire site and you are compelled to create a single file, put it in a partials folder and include the file in your layout file. Life's easy! Hold on!.. it's not that simple. What will you do when you want to highlight the page link on the navbar? Think about it and post your answer in the comments.

OK! fine, I will give you a hint. "Don't use Javascript to identify the href and dynamically changing the style of the navbar link". If you give up, expand the code below

View code

Use the if statements to identify the page. For example, in node js route, pass "home : true" and in the html, use if statement to enable the class. Add style to this class in css. See the code below for more info

app.get('/', (req, res) => {
  res.render("home", {
    home: true
  })
})
.nav-item .active {
  color: #fff;
  font-weight:bold;
}
<li class="nav-item">
  <a class="nav-link mx-2 {{#if home}}active{{/if}}" aria-current="page" href="/">Home</a>
</li>

5. Dynamic partials

The name says it all. Choose the kind of partial on the fly. Take a look at the below example in which we have an express server serving a route /blog-page. Usually blog pages stay the same for the sidebar, heading and footer / comments section and only the body changes. So, let's say the user is requesting a blog page /blog-page?page=express-handlebars. Create a partial handlebars file in a partial folder and name it express-handlebars.handlebars. Now inside the blogBody.handlebars view page, add the code {{>(whichPartial)}}. That's it! the page will be server dynamically. Moving forward, create more blogs with the same name as the URL search params (page).

app.get('/blog-page',(req,res)=>{
  var page = req.query.page
  if(!page) return res.redirect('404')
  res.render("blogBody", {
    whichPartial : function(){
      return `${page}`
    },
    layout:'blog'
  })
})
<div>
  {{>(whichPartial)}}
</div>

6. Pass Value To Select Tag

You can pass the values to the template such as updating the input values, headings, paras and alsmot every thing except a handful few. Select is one of them. For this we will take the help of helpers.

Lets take a scenario where you want to update the state in a select tag. From the database, we got the value "CT". For this, we need to build the options. See the code below

'stateHighlight' : function(val){
  var states = ["AL","AK","AZ","AR","CA","CO","CT","DE","DC","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"]
  var html = ''
  for(var s of states){
    if(val === s) html += `<option value="s" selected="selected">${s}</option>`
    else html += `<option value="${s}">${s}</option>`
  }
  return html
}
<select>{{{stateHighlight dbValue}}}</select>

7. Loop through Object & Array

In general Javascript, to loop through an array, you would use the good old for loop or foreach. But to loop throuh the object, you would first get the object keys in an array and then use it to loop through. In handlebars, you would simply use {{#each}}. See the code below for better understanding

var jsObject = {
  "Fav Heading": { 
    para: "Something about my fav heading" 
  },
  "Second Heading": { 
    para: "Reserved for second heading" 
  }
}

var jsArray = [
  { 
    "heading": "Fav Heading", 
    "para": "Something about my fav heading" }, 
  { 
    "heading": "Second Heading", 
    "para": "Reserved for second heading" }
]
<!-- For Looping through Object -->
{{#each jsObject}}
  <div>
    <h2>{{@key}}</h2>
    <p>{{this.para}}</p>
  </div>
{{/each}}
  
<!-- For Looping through Array -->
{{#each jsArray}}
  <div>
    <h2>{{this.h1}}</h2>
    <p>{{this.para}}</p>
  </div>
{{/each}}


Post a comment

I promise, I keep it clean *

Comments

Alert SVG Cookie Consent

This website uses cookies and similar technologies, to enhance your browsing experience and provide personalized recommendations. By continuing to use our website, you agree to our Privacy policy.