Using a view engine to render template files

Build web apps with NodeJS & Express

🕑 This lesson will take about 30 minutes

Dynamic web applications display content to the user that can vary depending on the user’s preferences, the request made to the server, and data from an API or database in the response served to the user. For example, if you visit the YouTube home page, the content that is displayed to you will be different to the content that is displayed to another user. The dynamic content displayed to you on YouTube would vary depending on videos you’ve liked, which channels you are subscribed to, your viewing history, and trending videos in your area.

We can display dynamic content to our web app’s users using the res.render() function, a view engine and template files.

The res.render() function renders a web page that can contain dynamic content including content from the server, an API, or a database, using a template file and view engine. The way that this works, is that you firstly create a template file that contains the structure or layout of a web page and its theme (eg. header, navigation bar, content area, footer) and some static content (eg. images, text) and then specify where dynamic content (coming from the server, an API or a database) will be displayed. This dynamic content can vary depending on the user, the request made by the user, or the response given by the server. In the server code, you would then specify which template file to use for the request and the data that will be passed through to the web page to be displayed where specified in the template file. We can then “fill in” the template file with data coming from an API or database.

A view engine (also known as a template engine or rendering engine) will need to be installed in your app to use the res.render() function. Examples of template engines include EJS and Pug. In this lesson, we will use the EJS view engine.

Step 1 - Create a views directory

The first step is to create a folder (directory) in your app folder to store your template files. We will call this folder ‘views’.

Screenshot showing a new folder/directory called 'views' inside the 'app' directory in Visual Studio Code's Explorer sidebar

Step 2 - Install a view engine

To render dynamic web pages using template files, we will need to install and specify a view engine (also known as a template engine or rendering engine) to use. There are a few different view engines that you can use, such as EJS and Pug. In this course, we will be using the EJS view engine because it allows us to write code for our templates that is very similar to HTML code.

To install EJS, start a new terminal and run the following command in the terminal (if using replit.com, open a new Shell tab and run the command):

npm i ejs

Note: If you’re using replit.com and can’t run the command in the Shell, open the package.json file and add "ejs": "latest" to the list of dependencies.

Step 3 - Specify the view engine to use

Now that we have installed the EJS view engine, we need to specify that we are going to use this view engine to render our templates. To do this, add the following code to your index.js file (after the first two lines of code):

app.set('view engine', 'ejs');

Step 4 - Create a template file

EJS template files contain a mix of normal HTML code and EJS code. Template files rendered using the EJS view engine must have a file name that ends with ‘.ejs’, for example, ‘index.ejs’. If you have already created HTML files, you can just rename them so they end with ‘.ejs’ instead of ‘.html’.

For now, the template file can contain regular HTML code, but later we will add more code so the web page can be filled in with data coming from the server when it is rendered. Here is the code used in this example for the ‘index.ejs’ template file in the views folder:

Tip: Install the ‘EJS Language Support’ extension in Visual Studio Code to get syntax highlighting for your EJS code.

Step 5 - Render the web page

The last step is to render the web page using the template file. Go back to your server code (the ‘index.js’ file). In the app.get(‘/’) route we created earlier, modify the code so it uses the res.render() function. When the home page is requested, we will render the ‘index.ejs’ template file by specifying ‘index’ when calling the res.render() function. Note that you do not need to add the ‘.ejs’ extension here. This is the line of code we will use:

res.render('index');

The image below shows the changes we have made to the ‘index.js’ file.

Screenshot showing changes to the index.js file. Scroll down to get the text version of the code.

Here is the complete server code for the ‘index.js’ file:

Start the server again using the node index.js command in the terminal and navigate to http://localhost:3000 in your web browser. The template file you used in your views folder will be rendered and the content will be displayed in the browser, as shown in the screenshot below.

Passing data from the server to your views

The strength of using templates is that we can create the structure and layout of our web app’s pages and then pass data in from the server (this data might come from an API or a database connected to the app) to add dynamic content to the page when it is rendered. For example, the home page (index.ejs) template might contain code for a paragraph of text <p>Welcome back, <%= username %> </p> and when the user ‘Joe’ logs in, the message “Welcome back, Joe” will be displayed. When the page is rendered, the data from the server will be used to fill in sections of the page where we have specified different variable names in the template file.

In the example below, we will display a welcome message to the user by passing through data from a variable called' ‘username’ on the server to the view. This can be achieved by specifying the data to pass through when calling the res.render() function. Between the { } curly brackets, we specify the name we will give the data and its value, for example res.render('index', {username: “Joe”}); . We can add more data between the brackets separated by commas, for example {username: “Joe”, location: “Sydney”} .

In your ‘index.js’ server code, use the following code:

Now go to your template file (‘index.ejs’ in the views folder) and modify the code to specify where the data that is passed into the view will be displayed on the page. We do this by placing the data between the <%= and %> characters.

Start the server again using the node index.js command in the terminal and navigate to http://localhost:3000 in your web browser. The template file you used in your views folder will be rendered and data passed through from the server will be displayed where you specified in the template, as shown in the screenshot below.

Using locals to prevent errors when data is not defined

When a variable has not been defined in the server code and you attempt to display its contents to the user in your template code, you will receive an error saying that the variable is not defined. For example, if we removed the username variable in the server code (index.js file), or didn’t set its value, or spelled the name of the variable differently in the server code (index.js file) to how it is spelled in the template code (index.ejs file), there will be an error saying the variable is not defined.

Try it out yourself - either change the name of the username variable in your server code, change the spelling of the variable name, or remove its value. Run the server again and you will see an error message “ReferenceError…username is not defined” like the one displayed below.

Screenshot showing message "ReferenceError: ... username is not defined"

Let’s say that we have a home page on our website that displays a greeting to users when they are logged in. If the user isn’t logged in, then the username variable won’t be defined and if we attempt to display the user’s undefined username in a greeting, then we will get an error “ReferenceError…username is not defined”.

So, there are two things we can do to address this problem - first, we can refer to locals.username in our template instead of just the variable username (as locals is always defined). If the username variable isn’t defined yet, then no error message will be displayed. However, as the variable is not defined, an empty value will be displayed to the user so they will get a message like “Welcome back, “ (with no username displayed after the comma, which is not ideal).

Use the following code in your template file (index.ejs) to try it out:

<p>Welcome back, <%= locals.username %> </p>

Screenshot showing text displayed to the user "Welcome back, "

We can address the issue above by setting a default value if a variable is not defined.

Specifying default values when data is not defined

When using locals, we can set a default value for data that has not been defined. For example, if our username variable has not been defined, we can set a default value for the username such as “user” or “customer”. To do this, we use || (the OR operator).

Try out the following code in your template file (index.ejs) to set a default value when data is not defined:

<p>Welcome back, <%= locals.username || 'user' %> </p>

When the variable is not defined, the default value will be displayed instead as shown in the image below.

Screenshot showing text displayed to the user "Welcome back, user"

We could also use an if/else statement to check if the username variable is defined and if so, display one message, otherwise if the username variable is not defined, display an alternative message instead.

In an EJS template, JavaScript code (such is if/else statements) can be written directly in the HTML code between the <% and %> tags, as shown below. These tags are used every time you are specifying the start and end of JavaScript code within your template’s HTML code.

<% if (locals.username){ %>
<p>Welcome back, <%= locals.username %> </p>
<% } else { %>
<p>Welcome. </p>
<% } %>

Note there is no = character in the <% tag whenever we are writing a JavaScript statement. The = character is added when we are just referring to a variable name and not actually writing a JavaScript instruction.

Now, using the code above, an entirely different message will be displayed to the user when the username variable is not defined.

Screenshot of web page displaying message "Welcome."

Here is the code for the EJS template file (index.ejs):

Next lesson: Serving static files