« Previous Tutorial Next Tutorial »

Now that we understand the basics of how Express routing works, let's take a look at how it renders views. We're going to dive right in, so if you need a refresher, make sure to check out JS Quick Hits 52, where we introduce Express, JS Quick Hits 53, where we cover what's happening in app.js, and last week's JS Quick Hits 54, where we go over routing.

This one runs a bit long, again. Sorry, this stuff is a bit more complicated than, like, "here's how Array.map works!" Open up /views/index.ejs and take a look. It's a pretty simple file. Here's all the code:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>

So, that's neat. It's basically HTML, with a few minor tweaks. For one thing, we're using single quotes for attributes instead of double quotes. This makes me sad, because it blurs the line between what's JS and what's HTML a little more than I'd like. It's also not necessary, so I'm changing that line to double-quotes, like this:

    <link rel="stylesheet" href="/stylesheets/style.css" />

We'll use single quotes in our JS, and double quotes in our HTML, because that's how I roll, and also because I think it makes for a handy visual identifier between what's code and what's markup. Same deal with JSX, when working with React.

Right, so … code. That brings us to the next minor difference. Those <% %> signs. As you can see, we're referencing something called title. Open up /routes/index.js real quick and look at this line:

  res.render('index', { title: 'Express' });

Well hey, look at that. There's our title. Our view is rendering it out when the page is generated. That happens because of the little = sign after the opening percent bracket, which tells EJS to output the value generated by the javascript code. We can use more complex logic than just giving it a single variable. In fact, let's do that below the welcome paragraph. Add this code:

    <p>
      The sum of five plus seven equals:
      <%= 5 + 7; %>
    </p>

That's pretty limited, obviously, since it can't really handle multiple lines of JavaScript. Fortunately, we can remove the = sign and do all the coding we want, just with the knowledge that we'll need to access any variables we create in a second line of code. Change that whole paragraph we just wrote to this code:

    <p>
      The sum of five plus seven equals:
      <%
        var sum = 5 + 7;
      %>
      <%= sum %>
    </p>

Obviously that's a little long-winded compared to our first approach, but the sky's really the limit in terms of what you can do, since everything in those <% %> blocks is just plain ol' JavaScript. You could get an Array of data from the back-end, and then manipulate that data in the template before displaying it, for example.

One other thing to note about <% %> brackets without an = sign is that you can use them to wrap HTML in JavaScript. Add this paragraph to your document:

    <p>
      <%
        if (Math.random() >= 0.5) {
      %>
          <span>Number is above or equal to 0.5!</span>
      <%
        }
        else {
      %>
          <span>Number is below 0.5!</span>
      <%
        }
      %>
    </p>

That code's ugly as the dog's behind, but it works. Keep refreshing the page and you'll see the output change. In my opinion it'd be better to just create the string in JS and then use an = sign to output the result, but it's good to know that you can pop in and out of JavaScript like that.

OK, now we're going to tie things together by creating a view that contains a form, another view that contains some thanks text, and a route that handles both views. Then we're going to add it to app.js and watch it work. We're going to speed through this with only a slight stop for explanation in a few spots. Ready?

Create /views/contact.ejs and in it, put this code:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel="stylesheet" href="/stylesheets/style.css" />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Send your message!</p>
    <form action="/contact" method="post">
      <fieldset>
        <input type="text" name="name" placeholder="Your Name" /><br />
        <textarea name="message" placeholder="Your Message" maxlength="250"></textarea>
      </fieldset>
      <button type="submit">Submit</button>
    </form>
  </body>
</html>

Save that file and create /views/thanks.ejs. Here's the code for this one:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel="stylesheet" href="/stylesheets/style.css" />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Your message was received!</p>
    <p><strong>Your Name: </strong><%= name %></p>
    <p><strong>Your Message: </strong><%= message %></p>
  </body>
</html>

Quick note: you don't have to keep repeating things like the HTML tag in every view. EJS supports imports of partial files. We just don't have time to discuss it right now. Instead, save this file and create /routes/contact.js. Start with these four lines:

var express = require('express');
var router = express.Router();

module.exports = router;

Now, below the requires but above the export line, add all of this:

/* GET index page. */
router.get('/', function(req, res, next) {
  res.render('contact', { title: 'Contact' });
});

/* POST to index page. */
router.post('/', function(req, res, next) {
  var querystring =
    'name=' + encodeURIComponent(req.body.name) +
    '&message=' + encodeURIComponent(req.body.message)
  ;
  res.redirect('/contact/thanks?' + querystring);
});

/* GET thanks page */
router.get('/thanks', function(req, res, next) {
  res.render('thanks', {
    title: 'Thanks',
    name: req.query.name,
    message: req.query.message,
  });
});

Right, that's a bunch of stuff. The / get is pretty straightforward. We're going to map that to /contact in app.js in a second. It just displays the view. All good there. Then we capture a POST to the same URL. Incoming form information is stored in the body property of req, with each variable coming from the name attribute in the HTML. We're using that to generate a querystring, which is the fastest and easiest way to display data on a page we're forwarding to. We then decode that querystring in the final GET, which will handle /contact/thanks, and pass it as variables for the EJS template to use.

Let's get all of this into app.js. Open that file and add a third router require, like this:

var contactRouter = require('./routes/contact');

Then find your app.use blocks that reference your imported routers, and add this below them:

app.use('/contact', contactRouter);

That's it. We're done! Save the file, and let's try things out. Restart your node server, unless you're using Nodemon (which you should be, because it's great), in which case it will have restarted for you. Head to http://localhost:3000/contact. Put some stuff into the boxes, click the submit button, and watch your routes work!

Pretty awesome, right? We've got views working with custom routes, we're handling form data … things are going well. Next week, we'll take a look at adding middleware to the equation. See you then!

As always, you can download example files for each of these tutorials from the JS Quick Hits github repo.

Enjoying these quick hits? You can get them five days early by subscribing to our weekly newsletter.

« Previous Tutorial Next Tutorial »

</%></%></%>