Using EJS Templates with Express

In the previous step we started using Express to create a web application. In this step, we explore EJS templates. There are many other templating packages that you can install with NPM, but EJS is one of the most popular them all.

You can use templates with your dynamic pages. Templates allow you to share a common HTML layout among many dynamic pages. There are many NPM packages that allow you to create templates. We'll be using one called EJS, which stands for 'embedded javascript'. You'll see that you can mix JavaScript code in an EJS template.

Run this command in the terminal to install the ejs package (make sure you are in the project folder):

npm install ejs

Create a folder named views in the project folder. It's a common practice to put your templates in a folder named 'views'.

In the views folder, create a file named default-layout.ejs and put this code in it:

<!DOCTYPE html> 
<html lang="en"> 
	<head> 
		<title><%= title %></title>
	  <meta charset="utf-8"> 
	  <meta name="viewport" content="width=device-width, initial-scale=1" /> 
		<link rel="stylesheet" type="text/css" href="/css/main.css">
		<script src="/js/main.js"></script>
	</head>
	<body>
		<header>
			<h1>Header</h1>
		</header>
		<nav>
			Nav Bar
		</nav>
		<div id="content">
			<main>
				<%- content %>
			</main>
		</div>
		<footer>
			Footer
		</footer>
	</body>
</html>

This is the template that we'll use for our dynamic pages. Note that there are placeholders (variables) inside the TITLE and MAIN elements. We'll inject content into theese placeholders when a page is requested. In EJS templates, placeholders are designated within <% and %> tags. If the placeholder will be replaced with HTML code, then you should put a dash directly after the opening tag. If the placeholder will be replaced with plain text (no HTML) then use an equals sign rather than a dash.

Now add this to the MIDDLEWARE section in app.js:

// specify that we are using 'ejs' templates in our app:
app.set('view engine', 'ejs');

This sets up our app to use EJS templates.

By default, EJS will look for .ejs files in the views folder, but if you wanted to use a different folder, you could add this under the line of code you just added: app.set('views', path.join(__dirname, '../some-other-folder')). But since we are using the default 'views' folder, we don't need to specify a different one.

Now, in app.js, update the route for the home page to make use of our ejs template, like so:

app.get('/', (req, res) => {
  res.render('default-layout', {
     title: "My Home Page",
     content: "<h1>Hello World from Express!</h1>"
  });
});

Run the app, or restart it, but entering node app.js in the terminal.

Load the homepage in your browser by visiting this URL: localhost:8080.

You should see the default layout template.

Now let's discuss the code for the route.

  1. We invoked the render() method of the response object.
  2. The first param that we passed in was the name of the template file that should be used (note that it doesn't require the .ejs file extension)
  3. The second param that we passed into render() is an object that contains properties that match the placeholders in our template. This is how you 'inject' content into a templage.

It's often useful to split a page layout template into parts that can be re-used. This allows you to re-use the parts in different layouts. Layout 'parts' should be put inside a folder named partials.

Inside the views folder, create a folder named partials.

Inside the partials folder, create a file named top.ejs, and put this code into it (this is the top portion of our page layout - which includes all the HTML that comes before the 'content' placeholder):

<!DOCTYPE html> 
<html lang="en"> 
	<head> 
		<title><%= title %></title>
	  <meta charset="utf-8"> 
	  <meta name="viewport" content="width=device-width, initial-scale=1" /> 
		<link rel="stylesheet" type="text/css" href="/css/main.css">
		<script src="/js/main.js"></script>
	</head>
	<body>
		<header>
			<h1>Header</h1>
		</header>
		<nav>
			Nav Bar
		</nav>
		<div id="content">
			<main>

Create another file in the partials folder, and call it bottom.ejs, then put this code into it (it's all the HTML in our layout that comes after the 'content' placeholder):

    </main>
  </div>
  <footer>
    Footer
  </footer>
</body>
</html>

Now you can update default-layout.ejs to look like this:

<%- include('partials/top') %>
<%- content %>
<%- include('partials/bottom') %>

In EJS, you can use the include() method to include 'partial' templates into another template.

If you reload the home page in the browser, you will not see any differences. But now you can re-use the top and bottom partial files in other layouts.

In the views folder, create a file named signup-layout.ejs and put this code into it:

<%- include('partials/top') %>
<form method="POST" action="/signup-confirmation">
  <label>First Name:</label>
  <input type="text" name="firstName">
  <br>
  <label>Last Name:</label>
  <input type="text" name="lastName">
  <br>
  <label>Email:</label>
  <input type="email" name="email">
  <br>
  <label>Password:</label>
  <input type="text" name="password">
  <br>
  <label>Confirm Password:</label>
  <input type="text" name="confirmPassword">
  <br>
  <input type="submit" value="Sign Up">
</form>
<%- include('partials/bottom') %>

Now add this code to the ROUTES section of app.js:

app.get('/signup', (req, res) => {
  res.render('signup-layout', {
     title: "Sign Up"
  });
});

Stop and restart the server, and then navigate to localhost:8080/signup in your browser. You should see the signup form.

In the next activity, we'll create a route that can handle submits from the sign up form.