People List EJS: Code-Along
The current People List app works for a small number of people, but it becomes increasingly tedious to add more and more. It is frustrating, because so much of the HTML is repeated, and all of the data exists in people.json. If only there were a way to pull the data from the JSON file into the HTML, so the server could dynamically generate each page and update the homepage accordingly... well, there is!
EJS (Embedded JavaScript) allows developers to use JavaScript directly in HTML templates, making them much more dynamic. The server passes a JavaScript object into the HTML based on the specific request and current data. It then renders a specific HTML page to send back up to the client for display!
Setting Up
- In the People List project folder, create a new folder named "views"
- Move the home.html file and person0.html file into the "views" folder
- Rename the files to home.ejs and person.ejs
app.js Updates
Make the following updates to the app.js file.
- Remove the
path
module import as it is no longer necessary - At the top of the file, add
require('ejs')
to install the library - After the
app
variable is initialized, use the code below to set the "view engine" to "ejs"app.set('view engine', 'ejs');
- In the body of the
homePage
function, remove the current command and replace it withresponse.render('home');
- In the
personPage
function, replace the render withresponse.render('person')
Remove everything from the
personPage
function except for the part where theindex
query parameter is obtainedfunction personPage(request, response) { let parsedUrl = url.parse(request.url, true); let index = Number(parsedUrl.query.index); response.render('person'); }
- Run the server, and make sure the homepage still loads along with the first person page (currently ignoring the index)
Passing the JSON Person
The goal is to have the program dynamically generate an HTML page for each person in the people.json file. To do that, it is necessary to pull the correct person object from the people.json
array based on the index, and pass it into the template.
Note: The people.json file must be saved in the same directory as the app.js file
- At the top of the file, import the
fs
module, storing it in aconst
variableconst fs = require('fs');
- Under that, use
fs.readFileSync
andJSON.parse
to put thepeople.json
array into a variable namedpeopleJson
let rawData = fs.readFileSync('people.json'); let peopleJson = JSON.parse(rawData);
- In the body of the
personPage
function, use theindex
query parameter to get the correct person from thepeopleJson
arraylet currentPerson = peopleJson[index];
- In the
response.render
function call, pass in a second parameter that is a new object with aperson
property ofcurrentPerson
response.render('person', { person: currentPerson });
- In the person.ejs file, add
<%= JSON.stringify(person) %>
somewhere for testing purposes - Run the server, load the
/person
page, and make sure that the object displayed changes based on theindex
query parameter!
Updating the Person Page Template
Now that the person
object is available in the person.ejs template, all that's left is updating the template to use the object properties! A value from the person
object can be implanted in the HTML like so:
<%= person.PROPERTY %>
- Replace the existing name with a dynamic piece of code that gets the
first_name
from theperson
, and adds thelast_name
of theperson
- Use
<%=
to start the EJS segment - Use
%>
to end the EJS segment - All the JavaScript in between those tags will be rendered in the HTML file!
- Use
- Replace the existing occupation with another dynamic EJS segment using
person.occupation
- Replace the image source (between
''
) with another dynamic EJS segment usingperson.avatar
- Check the
/person
page with some differentindex
values to see it update dynamically!
Changing the Background Color
The background color should be green if the person is alive, and red if the person is dead. It is possible to use if
statements in EJS scriptlets to accomplish this.
- Remove everything from the
head
element, and add an EJS scriptlet using<%
and%>
- For control flow, use
<%
with no equals sign because no JavaScript should render to the template - Instead of rendering within EJS, these statements use HTML dynamically
- For control flow, use
- Within the EJS scriptlet, enter the first line of an
if
statement checkingperson.alive
<% if (person.alive) { %>
- Under the EJS scriptlet, in the "body" of the
if
statement, add astyle
element with the CSS to set the background color of the page tomediumseagreen
<style> body { background: mediumseagreen; } </style>
- Under the HTML, add another EJS scriptlet to close off the
if
statement:<% } %>
- Load up the
/person
page, and make sure only alive people have green backgrounds! - In the
if
closing EJS scriptlet, add anelse
to handle dead people<% } else { %>
- Under the EJS scriptlet, in the "body" of the else, add a
style
element with the CSS to set the background color of the page tored
- Under the
</style>
, add another EJS scriptlet to close off theelse
statement - Load up the
/person
page, and make sure that dead people have red backgrounds!
Code
<html>
<head>
<% if (person.alive) { %>
<style>
body {
background: mediumseagreen;
}
</style>
<% } else { %>
<style>
body {
background: red;
}
</style>
<% } %>
</head>
<body>
<h3>Person Information</h3>
<p>Name: <%= person.first_name + ' ' + person.last_name %></p>
<p>Occupation: <%= person.job %></p>
<img src='<%= person.avatar %>' />
<p><a href='/'>Home</a></p>
</body>
</html>
Updating the Home Page Template
Now that the person page dynamically loads each individual person, update the home page so that the list of links is generated dynamically too!
Setting up the Loop
- In the app.js file, update the
homePage
function so that it passespeopleJson
when rendering the pageresponse.render('home', { people: peopleJson });
- In the home.ejs file, remove any
li
elements- They will be dynamically generated!
Within the
ul
, add an EJS scriptlet containing afor
loop that will loop through all of the people in thepeople
array<% for (let i = 0; i < people.length; i++) { %> <% } %>
- In the "body" of the
for
loop, add anli
- In the
li
, add an EJS segment to render the current index in thefor
loop:<%= i %>
- Load up the homepage, and make sure the proper number of list items appears!
Creating the Person Links
- Around the
i
EJS segment, add ana
element that will link to the person with the giveni
index<li> <a href='/person?index=<%= i %>'>Person</a> </li>
- Update the text of the Person link so that it also provides the index
- Update the text of the Person link so that it contains the first name of the person at the given index
- Update the text of the Person link so that it contains both the first and the last name of the person
<a href='/person?index=<%= i %>'> <%= people[i].first_name + ' ' + people[i].last_name %> </a>
- Load up the homepage, and make sure the links function properly!
Code
<html>
<body>
<h1>People List</h1>
<p>Welcome to the list of people</p>
<ul>
<% for (let i = 0; i < people.length; i++) { %>
<li>
<a href='/person?index=<%= i %>'>
<%= people[i].first_name + ' ' + people[i].last_name %>
</a>
</li>
<% } %>
</ul>
</body>
</html>
Final app.js Code
const express = require('express');
const url = require('url');
const fs = require('fs');
require('ejs');
const hostname = '0.0.0.0';
const port = 8080;
let rawData = fs.readFileSync('people.json');
let peopleJson = JSON.parse(rawData);
let app = express();
app.set('view engine', 'ejs');
function homePage(request, response) {
response.render('home', {
people: peopleJson
});
}
function personPage(request, response) {
let parsedUrl = url.parse(request.url, true);
let index = Number(parsedUrl.query.index);
let currentPerson = peopleJson[index];
response.render('person', {
person: currentPerson
});
}
app.get('/', homePage);
app.get('/person', personPage);
function listenCallback() {
console.log('Server running');
}
app.listen(port, hostname, listenCallback);