--- templateEngineOverride: false ---
Dr. Greg Bernstein
Updated March 21st, 2021
Express examples with simplest template example ExpressExamples.zip
Express Template Examples with inheritance ExpressTemplates.zip
Many web servers/frameworks keep site “information” in databases
This “information” is used to create web pages via Templates
This was one of the early uses of template systems in the web, other uses include static site generation, and client side rendering.
Express.js is an extremely popular JavaScript server framework.
Many template systems can work with Express.js
Nunjucks is very easy to use with Express.js
From ExpressExamples.zip
file templateEx.js
const express = require('express');
var app = express();
const nunjucks = require('nunjucks');
nunjucks.configure('templates', {
autoescape: true,
express: app
});
let host = '127.0.3.1'; // Choose a different loopback address
let port = '7373'; // Last digits of your NetID
let myName = 'Dr. B';
let info = {host: host, port: port, name: myName}
app.get('/', function (req, res) {
res.render('hello.html', info);
});
app.listen(port, host, function () {
console.log("Example app listening on IPv4: " + host +
":" + port);
});
From ExpressExamples.zip
file /templates/hello.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hello {{name}}</title>
</head>
<body>
<main>
<h1>Hi {{name}}</h1>
<h2>Server Running on {{host}} and port {{port}}</h2>
<p>That's it for now</p>
</main>
</body>
</html>
Provides for HTML content creation via variable substitution, loops, conditionals etc.
Provides for page layout via block substitution and inheritance.
A poorly styled site to inspire you to do better!
base.njk
TemplateNote block definitions and names from /templates/base.njk
in ExpressTemplates.zip
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
{% block metaStuff %}
<title>Galactic Wind Tours</title>
{% endblock %}
<link href="tour.css" rel="stylesheet">
</head>
<body>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/Tours">Coming Tours</a></li>
<li><a href="/NewsLetter">Newsletter Signup</a></li>
<li><a href="/Login">Login</a></li>
<li><a href="/about">About Us</a></li>
<li><a href="/addTour">Add Tour</a></li>
</ul>
</nav>
<main>
{% block main %}{% endblock %}
</main>
</body>
</html>
We create a template that extends and implements blocks in base.njk
{% extends "base.njk" %}
{% block metaStuff %}
<title>About Us</title>
{% endblock %}
{% block main %}
<h1 id="about-us">About Us</h1>
<section>
<h2 id="background">Background</h2>
</section>
<section>
<h2 id="technical-stuff">Technical Stuff</h2>
<p>Building Websites...</p>
<p>Astronomy and Astrophysics...</p>
</section>
{% endblock %}
Directory Structure
templates
: directory where all templates including base.njk
are kept.
public
: directory where static assets are kept
.
: root directory contains server program, mock data, package.json
, etc…
node_modules
: NPM packages
Initialization Code (tourServer.js
)
const express = require('express');
var app = express();
app.use(express.static('public')); // static middleware
const nunjucks = require('nunjucks');
nunjucks.configure('templates', { // template directory
autoescape: true,
express: app
});
/about
in the base.njk
template.<a>
links use GET
method based requestsapp.get('/about', function(req, res){
res.render('about.njk');
});
{"virtTours": [
{"name": "Kiting Neptune", "date": "Starting June 2022"},
{"name": "Windsurfing the Methane Lakes of Titan", "date": "Starting December 2022"},
{"name": "Kiting Jupiter's Great Red Spot", "date": "Starting June 2023"}
],
"phyTours": [
{"name": "Windsurf Foiling San Francisco Bay", "date": "May-September, Weekly by appointment"},
{"name": "'Bump and Jump' Windsurfing in the South Bay", "date": "Wind watch based tour"},
{"name": "Windsurf or Kite the Delta", "date": "Wind watch based tour"}
]
}
Renders tour data into HTML
{% extends "base.njk" %}
{% block metaStuff %}
<title>Current Tours</title>
{% endblock %}
{% block main %}
<h1 id="tours">Tours</h1>
<section>
<h2 id="virtual-tours">Virtual Tours</h2>
<ol>
{%for tour in tours.virtTours %}
<li>{{tour.name}} ({{tour.date}})</li>
{% endfor %}
</ol>
</section>
<section>
<h2 id="physical-tours">Physical Tours</h2>
<ol>
{%for tour in tours.phyTours %}
<li>{{tour.name}} ({{tour.date}})</li>
{% endfor %}
</ol>
</section>
{% endblock %}
Server code
const tours = require('./tours.json');
app.get('/Tours', function(req, res){
res.render('Tours.njk', {tours: tours});
});
General Approach
Newsletter signup path /NewsLetter
renders NewsLetter.njk
which has a form with action="newsSignup"
with method="GET"
Need a handler function for path /newsSignup
, GET method to process form information
Need NewsThanks.njk
to provide a personalized response to use to thank them for signing up.
{% extends "base.njk" %}
{% block metaStuff %}
<title>Newsletter Signup!</title>
{% endblock %}
{% block main %}
<h1>Galactic Wind Tours Newsletter</h1>
<section>
<h2>Signup for our Newsletter</h2>
<form action="newsSignup" method="GET">
<fieldset class="newsletter">
<legend>About You</legend>
<div id="SignUp">
<label>First Name</label><input type="text" name="fname"/>
<label>Last Name</label><input type="text" name="lname" />
<label>Email</label><input type="email" name="email"/>
<label>How did you hear about us?</label>
<select name="howHear">
<option>Newpaper</option>
<option>Facebook</option>
<option>Radio</option>
<option>Word of mouth</option>
</select>
</div>
<button type="submit">Submit</button>
</fieldset>
</form>
</section>
{% endblock %}
Server code to handle form submission
let newLetterSubs = []; // array to hold subscriber info
// This array would be replaced by database
app.get("/newsSignup", function(req, res){
newLetterSubs.push(req.query);
console.log(`News subscribers: ${JSON.stringify(newLetterSubs)}`);
res.render("NewsThanks.njk", req.query);
});
{% extends "base.njk" %}
{% block metaStuff %}
<title>Thanks for Signing up</title>
{% endblock %}
{% block main %}
<h1 id="about-us">Thanks for Signing up</h1>
<section>
<h2>Subscribed</h2>
<p>Thanks {{fname}} {{lname}} you've been subscribed to our
newsletter.</p>
<p>Also confirming that you heard about us from <em>{{howHear}}</em></p>
</section>
{% endblock %}