So far, we have built the basic Node.js app, configured Nunjucks, and learned about template inheritance. Now we can start creating additional parts of the page template in their own files and learn more Nunjucks tags while creating their content.
Prerequisities
First, create three additional templates in the partials directory: header.njk, navbar.njk, and footer.njk, and include them in the index.njk.
<!DOCTYPE html>
<html lang="en">
{% include "partials/head.njk" %}
<body>
{% include "partials/header.njk" %}
{% include "partials/navbar.njk" %}
<main>
{% block mainContent %}{% endblock %}
</main>
{% include "partials/footer.njk" %}
</body>
</html>
We also need to style our content, so for that, create a directory called public in the project root directory and inside it a styles subdirectory with a style.css file in it. Then add a link to that file in the head.njk,
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>{{ titleText }}</title>
<link rel="stylesheet" type="text/css"
href="styles/style.css">
</head>
modify the build script in package.json to copy the public directory,
"build": "npm run clean && npm run compile && cp -r src/views build/src/views && cp -r public build/public"
and add the relevant entry in index.ts to serve static files.
app.use(express.static(path.join(__dirname, '../public')));
Basic operations
Let’s start learning the basic operations that you are guaranteed to use on a daily basis.
Creating and modifying variables
To create or modify a variable in Nunjucks, you have to use the set tag. Let’s say that you wish the text in <title> to be a concatenation of two texts: one provided as a global variable and another being the particular page header. For that, provide the global variable in the index.ts as follows.
nunjucksEnvironment.addGlobal('titleMainText', 'My Website');
Then in the head.njk above the <head> tag sets the titleText variable that was previously provided by the indexController,
{% set titleText = titleMainText + " - " + headerText %}
and, of course, you have to remove the relevant entry from that controller, so now it will only provide the headerText.
If you are in a situation where you have to capture a whole block of content into a variable, there is an alternative syntax that uses the closing tag {% endset %}, like in this code that we add to the header.njk
{% set headerLink %}
<a href="{{ headerHref }}">{{ headerText }}</a>
{% endset %}
<header>
<h1 class="header">
{{ headerLink | safe }}
</h1>
</header>
Since by default Nunjucks will escape all output, if not configured differently, the above code would render the headerLink into a string instead of an actual hyperlink, so to avoid that, you have to mark it as safe. Remember also to update the indexController that provides the data for the Nunjucks template.
Conditional statements
The if statement in Nunjucks behaves exactly as if in JavaScript, but unlike in the latter, it requires a closing endif tag. Also, the else if statement has the form elif or elseif, which is simply an alias of elif. Here is an example of how to use it: In home.njk it takes a weekday variable provided by the indexController and sets a greeting text based on a particular condition. The result is used in a paragraph in the mainContent block.
{% if weekDay === "Friday" %}
{% set greetingText = "It's almost the weekend." %}
{% elif weekDay === "Saturday" or weekDay === "Sunday" %}
{% set greetingText = "Enjoy your weekend break." %}
{% else %}
{% set greetingText = "It's just another working day." %}
{% endif %}
{% block mainContent %}
<p>Today is {{ weekDay }}. {{ greetingText }}</p>
{% endblock %}
Similar to the ternary operator, you can use if as if it were an inline expression.
<header>
<h1 class="{{ "weekend-header" if weekDay === "Saturday" or weekDay === "Sunday" else "header" }}">
{{ headerLink | safe }}
</h1>
</header>
For loop
The for loop iterates over arrays and dictionaries, and just like the if statement, it requires a closing tag. If you wish to iterate over an array, the syntax is “for item in array,” and in the case of a dictionary, it is “for key, value in dictionary.” Let’s look at an example. We will create a simple navbar. The text and href of each element will come in a dictionary created in the indexController.
const menu: Map<string, string> = new Map();
menu.set('Home', '/');
menu.set('Texts', '/texts');
menu.set('Gallery', '/gallery');
menu.set('About', '/about');
res.render('mainContent/home', {
headerText: 'Hello World!',
headerHref: '/',
weekDay: weekDay,
menu: menu,
});
Then in navbar.njk, we create a <nav> element with a list inside, which is populated using the for loop and the menu dictionary.
<nav class="navbar">
<ul>
{% for key, value in menu %}
<li><a href="{{ value }}">{{ key }}</a></li>
{% endfor %}
</ul>
</nav>
Add styles to your liking and you’re done. Happy coding!