July 2, 2024

ExpressJS: Pug Template Inheritance

In this post we'll see how template inheritance is supported in Pug template engine.

Using template inheritance, you can create a hierarchy of templates where parent template may contain common functionality and child template can inherit that functionality from parent template and also free to add its own functionality.

Using template inheritance, you can write modular code and also reduce redundancy.

Template inheritance in Pug

Template inheritance works using the block and extends keywords in Pug template.

block keyword in Pug

Using block, you can create a placeholder in parent template that a child template may replace with some other functionality.

extend keyword in Pug

A child template inherits from the parent template using extends keyword.

Express.js - Pug inheritance example

In this example we'll create an ExpressJS app where pages will have a header which contains navigation menu and a footer. Since this header and footer is common for all the pages so we can create a parent template with header and footer code which can then be inherited by other pages which are going to be home.pug and user.pug.

There will also be stylesheets main.css and user.css where user.css is specific to user.pug 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;
}

views\layout.pug

This template acts as a parent template.

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title #{pageTitle}
    block stylesheets
      link(rel="stylesheet", href="/css/main.css")

  body
    header.header
      nav.nav
        ul.nav-menu
          li.nav-menu-item
            a(href="/") Home
          li.nav-menu-item
            a(href="/user") User
    block content

    footer.footer
      p © 2024 Company Name. All rights reserved.

Important points to note here-

  1. Header which contains a navigation menu and footer are kept in the parent template so that any template that extends it can get that functionality.
  2. Since other CSS files may be added in other pages so that is kept with in a block name stylesheets. By keeping it with in a block it can be replaced by child template.
  3. Same way there is a block named content as content will definitely be different for different pages.

views\home.pug

extends layout.pug
block content
  h2 Welcome to my site

Important points to note here-

  1. The template home.pug inherits from layout.pug parent template using the extends keyword.
  2. It gives its own code that should be put in place of block named content.
  3. Stylesheets block is not redefined here so it’ll use the parent’s default.

views\user.pug

extends layout.pug
block stylesheets
  link(rel="stylesheet", href="/css/main.css")
  link(rel="stylesheet", href="/css/user.css")
block content
  table
    tr
      th Name
      th Age
      th Gender
    each user in users
      tr 
        td= user.name
        td= user.age
        td #{user.gender}

Important points to note here-

  1. The template user.pug inherits from layout.pug parent template using the extends keyword.
  2. Since user.css stylesheet is also needed here so stylesheets block is overridden here.
  3. Similarly content block is also overridden to provide content specific to user page, which is a functionality to show user data in a table.

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');

// 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('/', (req, res) => {
  res.render('home', {pageTitle: 'Home 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}`)
})

Once you run it and access http://localhost:3000/ app displays the home page.

pug template inheritance

On clicking the user menu option.

pug template inheritance ExpressJS

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


You may also like

No comments:

Post a Comment