Preface

Goal: Feeding Data in ExpressJS, and Process in a Loop with Handlebars.

Consider continue with handlebars example. This should be the easiest part, because official express example is using handlebars.

Table of Content

  • Preface: Table of Content

  • Handlebars Case

  • What is Next ?

Official Documentation

Source Examples

You can obtain source examples here:


Handlebars Case

The handlebars case is the same, with the one utilizing grunt in previous article with a few differences.

  • express configuration

  • Using data to provide hyperlink in both navbar and sidebar.

Directory Structure

Consider an express structure with handlebars views.

❯ tree
.
├── app.js
├── package.json
├── public
│   ├── css
│   │   └── w3.css
│   ├── favicon.ico
│   └── js
│       └── script.js
└── views
    ├── css.hbs
    ├── html.hbs
    ├── index.hbs
    ├── javascript.hbs
    ├── partials
    │   ├── head.hbs
    │   ├── layout.hbs
    │   ├── navbar.hbs
    │   └── sidebar.hbs
    └── php.hbs

5 directories, 14 files

Handlebars: Example: Tree

The views structure is similar to previous case with grunt. I suggest that you have fast reading for this article first.

package.json

All you need to know is the devDependencies.

  "devDependencies": {
    "express": "^4.17.1",
    "handlebars": "^4.7.6"
  },

To begin with expressjs, you need to run npm install first.

app.js

You also need to a write a simple application in app.js.

// Basic Stuff
var express = require('express');
var path = require('path');
var app = express();

app.set('views', path.join(__dirname, 'views'));
app.use(express.static(path.join(__dirname, 'public')));
app.locals.pretty = true;

// Handlebars Configuration
var exphbs = require('express-handlebars');
app.set('view engine', 'hbs');
app.set('view options', { layout: 'partials' });
app.engine('.hbs', exphbs({
  layoutsDir   : 'views/partials/',
  partialsDir  : 'views/partials/',
  defaultLayout: 'layout',
  extname      : '.hbs'
}));

// Example Pages
var pages = [
  { link: '/',     short: 'Home', long: 'Home'  },
  { link: '/html', short: 'HTML', long: 'HTML Link' },
  { link: '/css',  short: 'CSS',  long: 'CSS Link' },
  { link: '/php',  short: 'PHP',  long: 'PHP Link' },
  { link: '/javascript', short: 'Javascript', long: 'Javascript Link' }
];

// Router
app.get('/', function(req, res) {
  res.render('index', { pages: pages, layout: false  });
  console.log("choice page is index");
});

const choices = ['index', 'html', 'css', 'php', 'javascript'];
app.get('/:page', function(req, res) {
  page = req.params.page;
  
  if (choices.includes(page)) {
    res.render(page, { pages: pages, layout: false });
    console.log("choice page is " +page);
  } else {
    res.send('404: Page not Found', 404);
  }
});

// Run, Baby Run
app.listen(3000);
console.log('Express started on port 3000');

The application is short enough to be self explanatory.

Handlebars Template Specific Code

Different with the pug or EJS example, we need a longer configuration for handlebars.

var exphbs = require('express-handlebars');
app.set('view engine', 'hbs');
app.set('view options', { layout: 'partials' });
app.engine('.hbs', exphbs({
  layoutsDir   : 'views/partials/',
  partialsDir  : 'views/partials/',
  defaultLayout: 'layout',
  extname      : '.hbs'
}));

Beware of the partials registering parts. Also if you are using extension other than .handlebars such as .hbs, then you require more effort to pick the correct configuration.

The same for every templates

To provide hyperlink in both navbar and sidebar, we need to setup the data in app.js as below:

var pages = [
  { link: '/',     short: 'Home', long: 'Home'  },
  { link: '/html', short: 'HTML', long: 'HTML Link' },
  { link: '/css',  short: 'CSS',  long: 'CSS Link' },
  { link: '/php',  short: 'PHP',  long: 'PHP Link' },
  { link: '/javascript', short: 'Javascript', long: 'Javascript Link' }
];

We will feed the data for each request.

app.get('/', function(req, res) {
  res.render('index', { pages: pages, layout: false  });
  console.log("choice page is index");
});

The sidebar will use long text, and the navbar will use short one.

Router

Almost the same for every templates

For simplicity, I put all the routes in app.js.

app.get('/', function(req, res) {
  res.render('index', { pages: pages, layout: false  });
  console.log("choice page is index");
});

const choices = ['index', 'html', 'css', 'php', 'javascript'];
app.get('/:page', function(req, res) {
  page = req.params.page;
  
  if (choices.includes(page)) {
    res.render(page, { pages: pages, layout: false });
    console.log("choice page is " +page);
  } else {
    res.send('404: Page not Found', 404);
  }
});

Beware that handlebars require the layout to be set as false.

  res.render('index', { pages: pages, layout: false  });

If the request does not contain any of the above page, express will send 404 error response.

Loop in Template

This time, consider alter a bit, both the sidebar and the navbar, so we can render each data in loop.

  <div class="w3-sidebar w3-bar-block w3-card w3-animate-left" 
       style="display:none" id="mySidebar">
    <button class="w3-bar-item w3-button w3-large"
       id="closeNav" >Close &times;</button>
    {{#each pages}}
    <a class="w3-bar-item w3-button"
       href="{{link}}">{{long}}</a>
    {{/each}}
  </div>
  <div class="w3-teal">
    <button class="w3-button w3-teal w3-xlarge"
            id="openNav">&#9776;</button>
    <div class="w3-container">
      <h1>My Page</h1>
    </div>
  </div>

  <div class="w3-bar w3-black">
  {{#each pages}}
    <a class="w3-bar-item w3-button"
       href="{{link}}">{{short}}</a>
  {{/each}}
  </div>

All you need to know is these lines:

  {{#each pages}}
    <a class="w3-bar-item w3-button"
       href="{{link}}">{{short}}</a>
  {{/each}}

Express: Loop in Handlebars

This will render a hyperlink, with result about the same with previous example.

Running Express

Running express is as easy as this command below.

$ node app.js

HTML: Hyperlink Example

Click any hyperlink on the example case, and you will get the response in console.log immediately.

Express: node app.js

You are ready to run a website, with expressjs backend, using handlebars.


What’s Next?

After ExpressJS we can move on to other popular NodeJS called KoaJS. Consider continue reading [ Template - Koa ].