This post is the fourth in a short series on using the PugJS view engine with NodeJS and ExpressJS. In the last part, we covered using PugJS to display dynamic data. In this post, we'll cover the concept of using includes (as named in the PugJS documentation). I prefer to call them "partials" and will do so in this article. Let's get started!
Starting Code
Below is our starting code (slightly modified since the last post).
//index.js
const express = require('express');
const userNames = ['Sean', 'George', 'Roger', 'Timothy', 'Pierce', 'Daniel']
const bestMovie = 'Casino Royale';
const licensedToKill = true;
const app = express();
app.set('view engine', 'pug');
app.get('/', (req, res) => {
res.render('index', {
userNames,
bestMovie,
licensedToKill,
title : "Home Page"
});
});
app.get('/about', (req, res) => {
res.render('about', {
userNames,
title : 'About'
});
});
app.listen(3000, () => {
console.log('Server listening on 3000');
});
//- main-layout.pug
<!DOCTYPE html>
html(lang="en")
head
title #{ title }
body
header
nav
ul
li
a(href="/") Home
li
a(href="/about") About
h1 This h1 is from the layout.
hr
block content
section
h2 This h2 is also from the layout
for user in userNames
li= user
block more_content
//- Index.pug
extends layouts/main-layout.pug
block content
if licensedToKill
p Bond is licensed to kill!
else
p Bond is NOT licensed to kill!
block more_content
p The best movie is #{ bestMovie }
p= bestMovie
//- about.pug
extends layouts/main-layout.pug
block content
p This content is from about.pug!
p About my cool site!
And here is our folder layout
project_folder
├── index.js
├── node_modules
├── package.json
├── package-lock.json
└── views
├── about.pug
├── index.pug
├── layouts
│ └── main-layout.pug
About Partials (Includes)
The concept behind includes is very simple. It gives us a mechanism to pull in the contents of one file into another. To do this, we use the include keyword followed by the path to a partial file. It is somewhat similar to the the "layout" concept discussed in the previous posts in this series. I like to think of the template system as a good way to create a general layout for your site whereas partials provide a good way to create modular components that can be reused. Let's see how we can integrate partials into our existing code.
Using a Partial For the Header
The header element in our main-layout file seems like a good candidate for a partial. In a real website, the header and nav elements could get a little complex and it would be nice to separate the header into a different file for easier readability and maintenance. To start, create a new folder under views called partials. Then create a new file in the partials folder called header.pug. Now cut the header element from main-layout and paste into header.pug. We'll also add an h1 with some text. It should look like this:
//- header.pug
header
nav
ul
li
a(href="/") Home
li
a(href="/about") About
h1 This page title is coming from header.pug -- #{ title }
In main-layout.pug include the header by adding this line where the header previously was. Be sure to indent properly. It should be indented one tab further than our body element:
include ../partials/header
Now if you view your page, you should see that we have the same end result. If you view the page source in the browser, you should see that we have well-formed HTML. If you don't have well formed html, there is an error in your pug syntax.
In our contrived example, there's not a lot of advantage to doing it this way. However, as previously noted, this could be pretty helpful in a more complex website. Let's do something slightly more useful.
Create a User Card
Now we'll create a reusable component for displaying a user. Create a new file in partials called user.pug with this content:
div.card
p= user
When this is translated into html, we will get a div with a class of card. In main-layout.pug, modify the users list to:
for user in userNames
include ../partials/user.pug
Now if we wanted to display a user anywhere in our site, we can just include our user.pug being sure that it has access to a user object.
As further practice, you could create a partial for a footer or another nav element. IMPORTANT NOTE: In these examples, I've only used partials in the main-layout file. However, this is not a requirement. We can use the include keyword in any pug file.
Avoid This!
You might think that we could change the first line of our index.pug to this:
include partials/main-layout.pug
However, this won't work! The html and body tags will be closed off too early and our html will be all jacked up!
Conclusion
In this post I've gone over using includes/partials in PugJS. We've seen how to split pieces of our views into separate files to aid reuse and readability. Hopefully this post was informative and, as always, corrections/comments/critiques are welcome!
Top comments (11)
Hello. This is well explained, and I have a question.
Let's say I want to dynamically change a tag when I include a pug file. Is it possible? For example, I have this form which I want to use in two different pages in my project but at home, it is in a modal. Its title is inside
.modal-header
with the tag.modal-title
, The form fields are inside.modal-body
and the submit button, inside.modal-footer
.Now, I need to load the same form in another page but without the modal tags. How can I do that?
I didn't cover this in my posts but I think a mixin is what you'd want to use in this case. Pug mixins are documented here. If you have troubles figuring out how to make that work, I'd be glad to write up another article showing a scenario similar to yours.
Another alternative would be to just use client-side JavaScript to add/remove CSS classes from your elements.
Hope that helps!
Did it.
I created a mixin for the modals (Actually I'm using two with different forms, I pass the params I need and it includes the forms. Even though it would be great if you write another article about it. Thank you.
Let me see what I can work up!
Done! Its quick & dirty but hopefully you'll find it useful.
Thank you. I'll share with you my solution.
Take a look. gist.github.com/Rincorpes/2a3f4d6e...
Did you check out my last post?
dev.to/nkratzmeyer/using-mixins-wi...
You can use the implicit attributes of a mixin to set attributes (including classes, id's, etc) on elements inside the mixin.
Yeah! I checked it but when I wrote this I had not read your post. I will implement it following your post. Thank you.
Thank you so much. I'm going to try it. I'll let you know.
Hello,
I'm a student and I'm looking for somebody to help me about 2 problems with pugjs.
Please, could you help me ? I have 2 problems... and I have to find a solution before saturday...
First, I want to display a picture for specific days. Moreover, I'll like creating a calendar.
It will be very kind if you could help me.
Best regards