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
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
})
})
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>
`
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}}
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
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>
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>
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>
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}}
Create a local file sharing server with realtime sync feature using Socket IO.
Most beautiful Navbars designed with tailwind css. Fully responsive templates.
Most beautiful dashboards designed with bootstrap. Inspired from dribble mostly.
Most commonly used HTML email templates. Welcome email, sign up, password reset etc.
Checkout our most downloaded payment page ui designed with bootstrap.
Detect user's inactivity and auto logout after certain timeout.
Parse and Upload CSV files online using Javascript (PapaParse)
Keep the user engaged and gain recurring website traffic. Includes templates.
How to attract more users to your website. A definite guide to webmasters today.
How to get a user's location using Javascript and other techniques available today.
A complete guide on HTML navbars and how to select the perfect one for the website.
Google core update that's released on May 25 2022 will take 1-2 for complete rollout.
A process to lure users to click certain links via posting intriguing images/headings.
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.