As the complexity of your templating project grows, it can be helpful
to refactor common pieces into auxiliary templates so they can be
reused. The {% include %}
and {% extends %}
tags support two very
different approaches to this, described below.
When your main template makes reference to auxiliary templates,
you’ll need to specify how the templating engine can find these
auxiliary templates. This is achieved using a template loader (see
help("loader")
).
There are different types of loader, but path_loader()
is the most commonly used. This allows you to specify the directory
where auxiliary templates are stored in files.
Imagine you have a main template that uses nested template
inheritance (content
inherits from
blog_post.html
, which in turns inherits from
base.html
). You might store these two auxiliary templates
in a templates directory:
/path/to/templates/
|-- base.html
|-- blog_post.html
When rendering the main template, you create the loader object as part of the engine configuration:
<- jinjar_config(loader = path_loader("path", "to", "templates"))
config <- render(content, !!!data, .config = config) output
The include
tag can be used to include an auxiliary
template and return the rendered contents of that file into the main
document. Included templates have access to the same variables as the
main template.
By default, an error is raised if the included template cannot be
found. You can ignore these errors by setting the
ignore_missing_files
argument in
jinjar_config()
.
As an example, we create an auxiliary file header.html
with contents:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My webpage</title>
</head>
and an auxiliary file footer.html
with contents:
</html>
And then the main template is rendered as:
{% include "header.html" %}<body>
Body</body>
{% include "footer.html" %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>My webpage</title>
</head>
<body>
Body</body>
</html>
Template inheritance allows you to build a base “skeleton” template that contains all the common elements of your document and defines blocks that child templates can override. This is a very powerful technique.
As an example, consider the following base template stored in
base.html
:
<!DOCTYPE html>
<html>
<head>
{% block head -%}<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
</body>
</html>
This base template declares three {% block %}
tags that
child templates can fill in: head
, title
and
content
. Note that the base template itself defines some
content for the head
block – we’ll show how a child
template can use this below.
A child template uses the {% extends %}
tag to declare
which parent template it builds upon. This should be the first tag in
the child template, so the templating engine knows it must locate the
parent template when rendering.
Building upon the base template example above, a child template might look like this:
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}<h1>Index</h1>
<p class="important">
Welcome to my blog!</p>
{% endblock %}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
<title>Index - My Webpage</title>
<style type="text/css">
.important { color: #336699; }
</style>
</head>
<body>
<div id="content">
<h1>Index</h1>
<p class="important">
Welcome to my blog!</p>
</div>
</body>
</html>
This child template defines the three blocks declared by the parent
template: head
, title
and
content
. In the case of the head
block, it
uses {{ super() }}
to render the contents of the
head
block defined by the parent template. If we were using
nested extends
tags, we could pass an argument to skip
levels in the inheritance tree (e.g. {{ super(2) }}
).