Dynamic Views and Templating with EJS
As your applications grow beyond static content, you will need to render web pages based on dynamic data, changing states, and user interactions. Rather than writing multiple copies of HTML files with slight differences, you can use a templating engine to generate pages dynamically. Templating engines make your application more flexible, maintainable, and scalable by separating layout from logic.
In this course, we will use EJS (Embedded JavaScript) as our templating engine. EJS works seamlessly with Node.js and Express, allowing you to embed JavaScript directly into your HTML files to create dynamic, reusable views.
What Is a Templating Engine?
A templating engine lets you define a template (an HTML file with placeholders or embedded code) and render it by injecting data from your application. The final output is a fully-formed HTML page sent to the user's browser. Templating engines offer several benefits:
- Dynamic Content: Display data that changes at runtime (user information, search results, etc.).
- Code Reusability: Use shared templates (layouts, headers, footers) across many pages.
- Separation of Concerns: Keep your server-side logic and client-side presentation organized and modular.
How EJS Works
EJS enables you to embed JavaScript-like logic directly into your HTML using special tags. However, it is important to note that EJS is not simply adding JavaScript to your HTML. Instead, it serves as a server-side templating language. The JavaScript code written within EJS templates is executed on the server, and the resulting plain HTML is sent to the client.
For instance, when a route handler invokes res.render(), Express processes the EJS file, evaluates the embedded code, and replaces it with the corresponding HTML output. The client only receives the final rendered HTML, ensuring that the server-side logic remains hidden.
EJS templates are typically stored in a directory named views. Each template file uses the .ejs extension and combines standard HTML with EJS tags to generate dynamic content efficiently.
Basic EJS Syntax
EJS provides several special tags. Each one serves a different purpose in controlling how data and logic are rendered in your HTML:
<%= %> Escaped Output
Outputs the result of a JavaScript expression, HTML-escaped for safety. Used to display user-generated content.
<h1>Hello, <%= user.name %>!</h1>
<%- %> Unescaped Output
Outputs raw HTML. Use this only when you are certain the content is safe to display. Usually used for trusted content we (our developers, our server) made or generated.
<div><%- user.bioHTML %></div>
Be cautious with <%- %>. If the data comes from users or untrusted sources, it may contain malicious HTML or scripts. Escape or sanitize this content before outputting it.
<% %> Logic Control Flow
Executes JavaScript without displaying any output. Ideal for conditionals and loops.
<% if (user.isLoggedIn) { %>
<p>Welcome back!</p>
<% } else { %>
<p>Please log in.</p>
<% } %>
<%# %> Comment
Adds a comment in the template that does not appear in the rendered HTML.
<%# This is an internal comment for developers %>
<%% %> Raw EJS Tag
Outputs a literal <% in the rendered HTML.
<%%= This will appear as <%= in the HTML %>
EJS Templating Engine Cheatsheet
This cheatsheet provides a quick reference to common EJS templating syntax and their usage:
| Syntax | Description |
|---|---|
<%= %> |
Outputs the value of the variable, escaped to prevent XSS (Cross-Site Scripting). |
<%- %> |
Outputs unescaped HTML (use with caution to avoid XSS). |
<% %> |
Executes JavaScript code without outputting anything. |
<%# %> |
Comment tag, does not output anything to the rendered HTML. |
<%% %> |
Outputs a literal <% in the rendered template. |
<? ?> |
Alternate syntax for <% %>, often used for compatibility with XML. |
Putting It Together: A Sample Template
The following is a sample index.ejs file using various EJS tags:
<!DOCTYPE html>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<!-- Display the user's name, escaped for safety -->
<h1>Hello, <%= user.name %>!</h1>
<!-- Conditional logic to check if the user is logged in -->
<% if (user.isLoggedIn) { %>
<!-- Display the number of new messages -->
<p>You have <%= user.messages.length %> new messages.</p>
<% } else { %>
<!-- Message prompting the user to log in -->
<p>Please log in to see your messages.</p>
<% } %>
<!-- Loop through the user's messages and display each one in a list -->
<ul>
<% user.messages.forEach((msg) => { %>
<li><%= msg %></li>
<% }); %>
</ul>
</body>
</html>
Rendering EJS Templates in Express
Once EJS is installed and configured, you can render templates from your route handlers using res.render(). Here is a complete example:
// Import the express module
import express from 'express';
// Create an instance of an Express application
const app = express();
// Set the view engine to EJS, so Express knows to use EJS for rendering templates
app.set('view engine', 'ejs');
// Define a route for the root URL ('/')
app.get('/', (req, res) => {
// Create a user object with some sample data
const user = {
name: 'Alex',
isLoggedIn: true,
messages: ['Welcome!', 'Do not forget to check your inbox.']
};
// Render the 'index' EJS template and pass the user object to it
res.render('index', { user });
});
// Start the server and listen on port 3000
app.listen(3000, () => {
console.log('Server is running on port 3000'); // Log a message when the server starts
});
In this example, the user object is passed to the index.ejs view. Inside the EJS template, you can access the values using EJS tags.
Next Steps
If you are curious to go deeper, explore the resources below. They provide additional context and examples to help you better understand how templating engines like EJS work inside Express applications.
If you are feeling adventurous, try implementing the sample code provided on this page to see how EJS templates work in practice. Hands-on experience will deepen your understanding of these concepts and enhance your skills.
Conclusion
Templating engines, like EJS, simplify the process of creating dynamic HTML content by allowing you to inject data and logic directly into your templates. They play a critical role in building server-side rendered web applications by bridging the gap between your application's data and its presentation layer.
While there are many templating engines available – such as Handlebars, Mustache, and Nunjucks – each with its own features and syntax, we will be using EJS in this class. EJS is widely used due to its simplicity, flexibility, and seamless integration with Express, making it an excellent choice for our learning goals.