Express + Handlebars: How to Include Subviews

Updated: January 18, 2024 By: Guest Contributor Post a comment

Introduction

When building web applications with Express.js and Handlebars, managing templates effectively is crucial to ensure maintainability and scalability. Including subviews within your views is an architectural best practice that compartmentalizes the UI, leading to cleaner and more modular code. In this tutorial, we’re going to cover how to leverage subviews in your Express.js applications using the Handlebars templating engine.

Setting Up an Express.js Project with Handlebars

Before diving into subviews, let’s ensure your environment is properly set up. Begin by initializing a new Node.js project and installing Express.js and express-handlebars, which is a Handlebars view engine for Express. Additionally, install nodemon for better development experience:

$ mkdir express-hbs-subviews
$ cd express-hbs-subviews
$ npm init -y
$ npm install express express-handlebars
$ npm install --save-dev nodemon

Edit your package.json to add a start script:

"scripts": {
 "start": "nodemon app.js"
},

Create an ‘app.js’ file and initialize your Express application with Handlebars as its view engine:

const express = require('express');
const { engine } = require('express-handlebars');

const app = express();

app.engine('handlebars', engine());
app.set('view engine', 'handlebars');
app.set('views', './views');

// ... additional Express middlewares and routes

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
 console.log(`Server is running on port ${PORT}`);
});

Understanding Partials in Handlebars

Before including subviews, it’s important to comprehend the concept of partials in Handlebars. Partials are smaller chunks of markup that can be reused across multiple templates. Create a directory named ‘partials’ inside your ‘views’ directory. For example, if you have a navigation bar common to all pages, make a file named ‘nav.handlebars’.

<nav>
 <!-- Navigation bar HTML -->
</nav>

To use this partial in your templates, firstly register it in your application:

const hbs = engine();
app.engine('handlebars', hbs);
app.set('view engine', 'handlebars');

hbs.handlebars.registerPartial('nav', fs.readFileSync('./views/partials/nav.handlebars', 'utf8'));

Now in any of your main Handlebars files, include the partial like so:

{{> nav}}

Including Subviews

Subviews are quite similar to partials but often pertain to larger sections of content that may even encapsulate partials themselves. For instance, consider a blog site that includes the same sidebar on multiple pages. You could create a ‘sidebar.handlebars’ in the ‘partials’ folder:

<aside>
 <!-- Sidebar content and maybe other partials like '{{> searchForm}}' -->
</aside>

Then, in your main views such as ‘home.handlebars’ and ‘about.handlebars’, you can include this sidebar subview:

{{> sidebar}}

This approach allows you to construct your page layouts with modular sections that can be mixed and matched as needed.

Passing Data to Subviews

Often you’ll need to pass context to your subviews or partials. For example, you can pass data from a route handler to a view with something like:

app.get('/', (req, res) => {
 res.render('home', {
   user: req.user,
   message: 'Handlebars is great!'
 });
});

In the ‘home.handlebars’ template, you can refer to these properties:

{{user.firstName}} - {{message}}

To pass this data down to subviews or partials, use the Handlebars built-in ‘with’ helper:

{{#with user}}
 {{> userProfile}}
{{/with}}

Dynamically Including Subviews

There might be scenarios where you want to dynamically determine which subview to include. You can do so by creating a custom helper. First, register a new helper:

hbs.handlebars.registerHelper('dynamicPartial', function (name) {
 return name;
});

Usage in your templates will look like this:

{{> (dynamicPartial subviewName) }}

Here, ‘subviewName’ is a variable representing the name of the partial you wish to include. It could be something passed from your route handler or conditioned within your view.

Conclusion

Including subviews in your Express and Handlebars templates is an excellent way to build maintainable and modular applications. By following the outlined strategies, you ensure that common elements are reused and state is appropriately managed and passed down, leading to a scalable architecture for your web applications. Experiment with these concepts and build robust Express.js applications with ease.