Getting a handle on the perfect tool for interpolating JavaScript code into your views.

Scroll down...




In the last lesson, we sent our application's response as a simple string, tucked inside of our callback function. It looked something like this:

app.get("/", function(req, res) {
  const superlative = "Groovy!"
  res.send("String Response! This is " + superlative)

This works great, however, many web pages are bit longer than a single line of text. Luckily, our forebears have met this foe and conquered it. We have templates!

Template engines allow you to write your markup in separate files just as you would for a static website, however they additionally let you interpolate JavaScript code and data by using a special interpolation syntax (which will vary according to the template engine you use). There is nothing too conceptually complex about template engines—you could achieve the same thing by concatenating a whole bunch of values together—but they are terribly useful.

Introduction to Handlebars

As with most parts of the JavaScript ecosystem, there is no lack of choice (and decision anxiety) when it comes template engines. We will arbitrarily select Handlebars. It's a very popular, well-maintained templating language that sports a very simple, unobtrusive syntax.

Handlebars uses double curly braces to surround its interpolated code. Here's what interpolating some challenging math looks like:

<div class>
  2 + 8 = {{2 + 8}}

When this template is evaluated, you'll see 2 + 8 = 10. Just what we wanted! Now we can simply interpolate some JavaScript code rather than fry our brain with mental math.

Connecting Handlebars to Express

First, we must install Handlebars with npm. This time, for no particular reason, let's use the terse version of our favorite npm command.

npm i hbs -S

There's one more simple yet necessary task before we're good to go; we have to tell Express which view engine we will be using. This is done by adding the following line to our index.js file.

app.set('view engine', 'hbs')

Rendering Templates

It's now possible to render templates in our application, but how do we do that? We will first need a top-level views directory to store our template files, the path to the views folder can be set similarly to how we set our view engine above, yet the default is fine in this case. Then we will create our greeting.hbs template file inside of this new folder. It should look like this:

<h1>Hello Viking!</h1>

We aren't yet taking advantage of JavaScript interpolation. Let's make sure our template renders first. Update the first callback function, the one for the index route ('/'), to look like this:

app.get('/', function (req, res) {

All we have done is replaced the method send with the method render and passed in the name of our template file rather than a string. The render method tells Express to find the template with this name in the views folder and send it back as the response. If all went well, the page should still display "Hello Viking!" when you restart your server—though now the font should be a wee bit larger.

res.render and res.send are very similar. They both send back a response to the client. res.send allows one to send back a string while res.render will send html back (also marked as a string, but it will be the result of compiling the template with the given name).

Passing Data to A Template

For our final trick, we will change the '/person/:personName' route to use the same template as our root route. We will need to get our name variable into the template somehow, this can be done by passing an object as the second argument to render. Each of the objects keys will be accessible within the given template as variables. Let's update our '/person/:personName' callback.

app.get('/person/:personName', function (req, res) {
  const personName = req.params.personName
  res.render('greeting', { name: personName }) // the second argument is the data that will be embedded in the template

As well as the greeting.hbs file.

<h1>Hello {{name}}!</h1>

Restarting the server, your page should still work. Of course, now we must update our first callback again.

app.get('/', function (req, res) {
  res.render('greeting', { name: "Viking" })

Lovely! It's completely reusable between the two callback functions. Who could have seen that coming?

Code Review

Here's the current state of our "Hello World" application.

const express = require('express')
const app = express()

app.set('view engine', 'hbs')

app.get('/', function (req, res) {
  res.render('hello', { name: "Viking" })

app.get('/person/:personName', function (req, res) {
  const personName = req.params.personName
  res.render('hello', { name: personName })

app.listen(3001, function () {
  console.log('Odin is listening on port 3000!')

Wrapping Up

Templates are a great way of dealing with large views in need of a little (or lots) of interpolation. Even though they've added some complexity and indirection to this very basic example, I hope you can imagine how they might prove useful in even a slightly more complicated project. It's okay if you don't believe me, you'll get a chance to try them out for yourself soon enough.

Sign up to track your progress for free

There are ( ) additional resources for this lesson. Check them out!

There are no additional resources for this lesson just yet!

Sorry, comments aren't active just yet!