July 17, 2024

ExpressJS: EJS Partials

In EJS template engine there is no support for inheritance like you have in Pug through block and extends keywords. So, you can't create layouts using blocks in EJS as you can in Pug template inheritance. But the functionality to include smaller files to create a larger file is very important in order to promote code reuse, making maintenance of code easier as you don't need to change code in every page. In EJS you can have the similar functionality by including smaller files to create a bigger file.

In EJS template terminology these are known as EJS partials which are reusable components that can be combined to create a larger view.

Syntax for include in EJS

You can include partial files by using the following command.

<%- include( PARTIAL_FILE ) %> 

Here PARTIAL_FILE is the file path relative to the template where partial file is included.

Note the use of <%- %> tags which allows you to output unescaped HTML content. When you use this tag <%= %>, if you have any HTML it will be rendered as string (HTML code itself) not as HTML display.

Express.js - EJS partials example

In this example we'll create an ExpressJS app where pages will have a navigation menu and footer. Since this menu and footer is common for all the pages so we can create partial files with navigation menu and footer code which can then be included in other pages which are going to be home.ejs and user.ejs.

There are also stylesheets main.css (for styling menu and footer) and user.css (for styling table which shows user data) where user.css is specific to user.ejs template.

public\css\main.css

.header{
    width: 100%;
    height: 3rem;
    text-align: center;
    background-color: #6d70a8;
    padding: 1 2rem;
    margin-bottom: 1rem;
}

.nav{
    height: 100%;
    display: flex;
    align-items: center;
}

.nav-menu{
    list-style: none;
    display: flex;
}

.nav-menu-item{
    margin: 0 2rem;
    padding: 0;
}

.nav-menu-item a{
    text-decoration: none;
    color: white;
}

.footer { 
    text-align: center;
 
    position: absolute; 
    width: 100%;
    bottom: 0; 
    left: 0; 
    background-color: #6d70a8;
    color: white;
}

public\css\user.css

table, td, th {
  border: 1px solid;
}
table {
  width: 80%;
  border-collapse: collapse;
}

Within views folder let's create a sub-folder named partials to save partial files.

views\partials\navigation.ejs

<header class="header">
  <nav class="nav">
    <ul class="nav-menu">
      <li class="nav-menu-item">
        <a href="/">Home</a></li>
      <li class="nav-menu-item">
        <a href="/user">User</a>
      </li>
    </ul>
  </nav>
</header>

views\partials\footer.ejs

<footer class="footer">
  <p>&copy; 2024 Company Name. All rights reserved.</p>
</footer>

views\home.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= pageTitle %></title>
    <link rel="stylesheet" href="/css/main.css">
  </head>
  <body>
    <%- include('partials/navigation.ejs') %>
    <h1>EJS Demo</h1>
    <p>Welcome <strong><%= userName %></strong></p>
    <%- include('partials/footer.ejs') %>
  </body>
</html>

Since navigation and footer are needed so those files are included at the appropriate location within the body.

views\user.ejs

This template is used to show user data by iterating users array. In this file also navigation and footer are needed so those files are included.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title><%= pageTitle%></title>
    <link rel="stylesheet" href="/css/user.css">
    <link rel="stylesheet" href="/css/main.css">
  </head>
  <body> 
    <%- include('partials/navigation.ejs') %>
    <h2>Using for-of to loop array</h2>
    <table>
      <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Gender</th>
      </tr>
      <% for(let user of users) {%>
      <tr> 
        <td><%= user.name%></td>
        <td><%= user.age%></td>
        <td><%= user.gender%></td>
      </tr>
      <%}%>
    </table>
    <%- include('partials/footer.ejs') %>
  </body>
</html>

app.js

const express = require('express');
const app = express();
const port = 3000;
const path = require('path');

// To serve static files like CSS
app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// Hardcoded user data
const users = [{name:'Reene', age: 28, gender:'F'}, 
    {name:'Badal', age: 34, gender:'M'},
    {name:'Vidyut', age: 25, gender:'M'},
    {name:'Dhriti', age: 29, gender:'F'}
]

// for home page
app.get('/', (req, res) => {
    res.render('home', {pageTitle:'HomePage', userName:'TestUser'});
})

// for user page
app.get('/user', (req, res) => {
    res.render('user', {users: users, pageTitle: 'User Page'});
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

On running this file- node app.js and then accessing the URL- http://localhost:3000/

EJS Partials

Clicking on user menu option.

Express.js EJS partials

That's all for the topic ExpressJS: EJS Partials. If something is missing or you have something to share about the topic please write a comment.


You may also like

ExpressJS: EJS Template Iteration Examples

In the post ExpressJS: EJS Template Engine Integration With Examples we have seen how you can use EJS template with Express.js app. In this post we'll see how to iterate over an array or object in EJS template.

Iteration in EJS

EJS template uses JavaScript code with in the scriptlet tags <% %>. Which means you can use the same loops which are used in JavaScript to iterate an array or object in EJS.

Loops that can be used are-

  1. Normal for loop
  2. While loop
  3. for-of to iterate array
  4. forEach to loop array
  5. for-in to iterate an object

Express.js - EJS iteration example

Let's assume we have an array of User objects which we want to iterate and display in our view named 'user.ejs' which is created as a EJS template.

app.js

const express = require('express');

const app = express();

const port = 3000;
const path = require('path');

// To serve static files like CSS
app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// Hardcoded user data
const users = [{name:'Reene', age: 28, gender:'F'}, 
    {name:'Badal', age: 34, gender:'M'},
    {name:'Vidyut', age: 25, gender:'M'},
    {name:'Dhriti', age: 29, gender:'F'}
]

app.get('/user', (req, res) => {
    res.render('user', {users: users, pageTitle: 'User Page'});
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

As you can see in the code there is an array named users that contains user objects. There is also a mapping '/user' which renders the user.ejs template and values for variables users and pageTitle in the view are also passed.

public\css\user.css

CSS used for styling table.

table, td, th {
  border: 1px solid;
}
table {
  width: 80%;
  border-collapse: collapse;
}

views\user.ejs

<!DOCTYPE html>
<html lang="en">
  <head>
    <title><%= pageTitle%></title>
    <link rel="stylesheet" href="/css/user.css">
  </head>
  <body> 
    <h2>Using while loop</h2>
    <table>
      <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Gender</th>
      </tr>
      <% 
      let i = 0;
      while(i < users.length) {%>
      <tr> 
        <td><%= users[i].name%></td>
        <td><%= users[i].age%></td>
        <td><%= users[i].gender%></td>
      </tr>
      <% i++;
      }%>
    </table>
    <h2>Using normal for loop</h2>
    <table>
      <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Gender</th>
      </tr>
      <% for(let i= 0; i < users.length; i++) {%>
      <tr> 
        <td><%= users[i].name%></td>
        <td><%= users[i].age%></td>
        <td><%= users[i].gender%></td>
      </tr>
      <%}%>
    </table>
    <h2>Using for-of to loop array</h2>
    <table>
      <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Gender</th>
      </tr>
      <% for(let user of users) {%>
      <tr> 
        <td><%= user.name%></td>
        <td><%= user.age%></td>
        <td><%= user.gender%></td>
      </tr>
      <%}%>
    </table>
    <h2>Using forEach to loop array</h2>
    <table>
      <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Gender</th>
      </tr>
      <% users.forEach(user => {%>
      <tr> 
        <td><%= user.name%></td>
        <td><%= user.age%></td>
        <td><%= user.gender%></td>
      </tr>
      <%});%>
    </table>
  </body>
</html>

In the code all of the mentioned loops are used to show iteration of an array in EJS template. For each loop, JavaScript code is enclosed with in the scriptlet tags.

So, the loop and starting curly bracket is in a scriptlet tag

<% for(let user of users) {%>

Then the closing curly bracket is in a scriptlet tag

<%}%>

When you run the file- node app.js and then access the URL- http://localhost:3000/user

EJS Template Iteration Example

EJS object iteration ExpreeeJS example

If you want to iterate an object and extract the (key, value) pairs then you can use for-in loop.

app.js

const express = require('express');

const app = express();

const port = 3000;
const path = require('path');

// To serve static files like CSS
app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// Hardcoded user data
const user = {name:'Reene', age: 28, gender:'F'};

app.get('/user', (req, res) => {
    res.render('user', {user: user, pageTitle: 'User Page'});
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

views\user.ejs

<!DOCTYPE html>
<html lang="en">
  <head>
    <title><%= pageTitle%></title>
    <link rel="stylesheet" href="/css/user.css">
  </head>
  <body> 
    <h2>Using for-in loop</h2>
    <ul>
      <% for(let key in user) {%>
        <li><%=key.charAt(0).toUpperCase() + key.substr(1).toLowerCase() + ': ' + user[key]%></li>
      <%}%>
    </ul>
  </body>
</html>

When you run the file- node app.js and access the URL- http://localhost:3000/user

you'll get the result as-

Using for-in loop

    Name: Reene
    Age: 28
    Gender: F

That's all for the topic ExpressJS: EJS Template Iteration Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

July 16, 2024

ExpressJS: EJS Template Engine Integration With Examples

The post ExpressJS Template Engines Introduction gives an introduction to template engines that can be used with Express.js. In this article we'll see how to use EJS template engine.

Installing EJS

You can install EJS by using the following command.

npm install ejs

Settings in Express.js for using EJS

You need to configure EJS as the view engine in Express.js app.

app.set('views', './views')

This setting sets the views directory in the application root directory as the location where template files are saved. Template engine will search this directory to locate the template that has to be transformed. By default template engine searches in 'views' directory so you can omit this configuration if you are saving template files in 'views' directory.

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

This setting sets EJS as the template engine.

Writing EJS template

You can use express-generator to create project structure which gives a views directory and with in that folder you can create files with .ejs extension.

EJS templates are very similar to HTML only difference is the use of template tags <% %> to produce dynamic content.

views\home.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= pageTitle %></title>
  </head>
  <body>
    <h1>EJS Demo</h1>
    <p>Welcome <strong><%= userName %></strong></p>
  </body>
</html>

As you can see template tags are used at two places with in the template.

<title><%= pageTitle %></title>

<p>Welcome <strong><%= userName %></strong></p>

app.js

const express = require('express');

const app = express();

const port = 3000;
const path = require('path');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.get('/', (req, res) => {
    res.render('home', {pageTitle:'HomePage', userName:'TestUser'});
})

Some important points to note here-

  1. Properties are set for template engine using app.set() method.
  2. In res.render() method template name is passed as the first parameter and as a second parameter an object is passed which has values set for the variables in the template with variable name as key.

This is the generated HTML that you can view by going to page source.

<!DOCTYPE html>
<html>
  <head>
    <title>HomePage</title>
  </head>
  <body>
    <h1>EJS Demo</h1>
    <p>Welcome <strong>TestUser</strong></p>
  </body>
</html>

That's all for the topic ExpressJS: EJS Template Engine Integration With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

July 5, 2024

ExpressJS: Pug Case Statement

In the post ExpressJS: Pug Conditionals we have seen how we can write conditions in Pug template using if else. One more way to write condition is using case statement in Pug template.

The case statement is a shorthand for JavaScript's switch statement. It takes the following form-

case variable
  when value1
    // Code block
  when value2
    // Code block
  ..
  ..
  default
    // Code block for default

Variable may be of type number or string.

Express.js - Pug case example

In the example pug template, we iterate over an array of date objects which has properties date and country. By using case with date.country we format the date in different formats based on the country.

app.js

const express = require('express');

const app = express();

const port = 3000;
const path = require('path');
app.locals.date = require('date-and-time');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

const dates = [{date:'2003-08-19', country: 'USA'}, 
    {date:'2012-11-23', country: 'UK'},
    {date:'2023-02-11', country: 'India'},
    {date:'2023-09-17', country: 'Germany'},
    {date:'2023-09-17', country: 'Hungary'}
]

app.get('/country', (req, res) => {
    res.render('country', {dates: dates, pageTitle: 'Country Page'});
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

Important points to note here-

  1. Code uses date-and-time JS library which is just a collection of functions for manipulating date and time.
  2. Install date-and-time library using the command-
    npm i date-and-time
  3. Since we need to use date-and-time functions in the template so it is imported using app.locals. The app.locals object has properties that are local variables within the application, and will be available in templates rendered with res.render

views\country.pug

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title #{pageTitle}
  body
    h3 Case Statement Demo 
      ul
        each d in dates
          case d.country
            when "India"
            when "UK"
              li= date.format(new Date(d.date),'DD/MM/YYYY') + ' ('+d.country + ')'
            when "USA"
              li= date.format(new Date(d.date),'MM-DD-YYYY') + ' ('+d.country + ')'
            when "Germany"
              li= date.format(new Date(d.date),'YYYY-MM-DD') + ' ('+d.country + ')'
            default 
              li= date.format(new Date(d.date),'YYYY/MM/DD') + ' ('+d.country + ')'

In the code, iteration is done over the dates array and case statement is used with d.country. Based on the value of the country different formats are passed with date.format() which is a function from date-and-time JS library used in the template.

Now if you run the app.js and access the URL- http://localhost:3000/country

Pug Case Statement

That's all for the topic ExpressJS: Pug Case Statement. If something is missing or you have something to share about the topic please write a comment.


You may also like

How to Add 404 Error Page in Express.js

This tutorial shows how to add a 404 (page not found) error page when using ExpressJS routing. If you try to access any path that is not matched to any route then 404 error page should be displayed.

Adding 404 error page

If you have created your project structure using express-generator then you will have separate route folder for keeping route files where you can use express.Router() to create route definitions.

Let's create a separate error HTML too and send that in the case there is no matching route.

views\error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Error Page</title>
</head>
<body>
    <h3>Page not found</h3>
</body>
</html>

In the app.js file after adding the routes as middleware you can add a separate Express middleware for sending response with status as 404 (not found) and file as the created error.html file.

app.js

const express = require('express');
const app = express();

const port = 3000;
const path = require('path');

const usersRouter = require('./routes/users');
const productRouter = require('./routes/products');
// adding routes
app.use(usersRouter);
app.use(productRouter);
// for error page, add after other routes
app.use((req, res, next) => {
    res.status(404).sendFile(path.join(__dirname, 'views', 'error.html'));
})
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

With this if you run app.js and try to access any route which doesn't exist you should get error page as response with status code 404.

404 Error Page in Express.js

That's all for the topic How to Add 404 Error Page in Express.js. If something is missing or you have something to share about the topic please write a comment.


You may also like

July 3, 2024

ExpressJS: Pug Conditionals

In the post ExpressJS: Pug Template Engine Integration With Examples we have seen how you can use Pug template with Express.js app. In this post we'll see how to use conditional statement in Pug template.

Conditional syntax in Pug template

Using conditional statement, you can execute a block of code based on whether the evaluated condition is true or false.

Pug template has if, else if, else conditional statement.

You can use only if - else

If condition
	…
	…
else
	…
	…

Which can be explained as; if the specified condition evaluates to true execute the if code block. If the specified condition evaluates to false execute the else code block.

You can also have multiple else if blocks if there are more than one condition to be evaluated.

If condition
	…
	…
else if condition
	…
	…
else if condition
	…
	…

else
	…
	…

Express.js - Pug if-else condition example

In the example pug template, we iterate over an array of product objects and display product.name in different colours based on the sales of the products. For that there are conditions based on product.sales.

app.js

const express = require('express');

const app = express();

const port = 3000;
const path = require('path');

// To serve static files like CSS
app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

const products = [{name:'Trousers', sales: 150}, 
    {name:'Sport Shoes', sales: 40},
    {name:'Sneakers', sales: 200},
    {name:'T-Shirts', sales: 70}
]

app.get('/product', (req, res) => {
    res.render('product', {products: products, pageTitle: 'Product Page'});
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

public\css\color.css

Stylesheet for text colours.

.green{
  color: green;
}

.red{
  color: red;
}

.blue{
  color: blue;
}

views\product.pug

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title #{pageTitle}
    link(rel="stylesheet", href="/css/color.css")
  body
      h3 Conditional Statement Demo 
      ul
        each product in products
          if product.sales >= 100
            li.green #{product.name}
          else if product.sales < 50
            li.red #{product.name}
          else 
            li.blue #{product.name}

That's all for the topic ExpressJS: Pug Conditionals. If something is missing or you have something to share about the topic please write a comment.


You may also like

express.static() in Express.js

In every web application we do have static content such as images, CSS files, and JavaScript files that has to be rendered. In Express.js you can use the express.static built-in middleware function to serve such static files.

express.static syntax

express.static(root, [options])
  • root- This argument specifies the root directory from which to serve static assets.
  • options- You can get more information about options argument here.

For example-

app.use(express.static(path.join(__dirname, 'public')));

By providing the above middleware function, static files are served by combining root URL with the provided root directory. Static files are accessed using path relative to PROJECT_ROOT_DIR/public, you don't need to provide the absolute path of each static asset. This makes it convenient to access such static files and avoids hardcoding absolute paths.

express.static example

Suppose you have a public directory with in your project root directory and with in public you have sub-directories css and images. With in these sub-directories, you have few stylesheets and images respectively.

express.static() in Express.js

In order to serve these static assets you can set the public directory using the express.static() middleware.

app.js

const express = require('express');
const app = express();
const port = 3000;
const path = require('path');

// To serve static files like CSS
app.use(express.static(path.join(__dirname, 'public')));

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

app.get('/', (req, res) => {
    res.render('user');
})

Since the route setup here renders user.ejs when root URL is accessed so let's create a user.ejs file.

views\user.ejs

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>User Page</title>
        <link rel="stylesheet" href="/css/style.css">
        <link rel="stylesheet" href="/css/user.css">
    </head>
    <body> 
        <h2>User Data</h2>
        <table>
            <tr> 
                <td>Reene</td>
                <td>28</td>
                <td>F</td>
            </tr>
            <tr> 
                <td>Badal</td>
                <td>34</td>
                <td>M</td>
            </tr>
        </table>
        <img src="/images/testimage.png" />
    </body>
</html>

As you can see the path to style.css here is given as "/css/style.css". As per my project structure css directory resides in "/myexpressapp/public/css" but the path to css in ejs file is relative to public directory which is possible because of setting it using express.static.

Same way for image, path used is "/images/testimage.png"

That's all for the topic express.static() in Express.js. If something is missing or you have something to share about the topic please write a comment.


You may also like