-
Notifications
You must be signed in to change notification settings - Fork 0
Slicing Templates
- Static vs Dynamic Templates
- Template Slicing
Pedestal provides a very flexible way to write template source files. In order to use these templates in your application we need to extract them from the source.
In our ClojureScript code, we would like to have a map were we can look up a template, add it to the DOM and make changes to it. Pedestal provides functions to help us extract templates from source files.
The file
app/src/tutorial_client/html_templates.clj
contains the code which does this.
(defmacro tutorial-client-templates
[]
{:tutorial-client-page (dtfn (tnodes "tutorial-client.html" "tutorial" [[:#other-counters]])
#{:id})
:other-counter (dtfn (tnodes "tutorial-client.html" "other-counter") #{:id})})This is a Clojure macro but you can think of it as a normal Clojure
function. The only thing that is different about this function is that
it will be run at compile time. When we compile our ClojureScript
code, any call to tutorial-client-templates will be replaced with
the return value of this function.
This code uses functions form the io.pedestal.app.templates
namespace.
The tnodes function converts a template in a file into a sequence of
Enlive nodes.
(tnodes "tutorial-client.html" "other-counter")The third argument to tnodes is a vector in Enlive selectors that we
would like to have "cleared". This means that the contents of the
these nodes will not be included. This is helpful when you have some
example data in the HTML that you don't want in the actual template,
as is the case here, when you do not what to include an inner template
in an outer one.
(tnodes "tutorial-client.html" "tutorial" [[:#other-counters]])Because this is a sequence of Enlive nodes we can perform any other transformations that we would like.
There are two ways to turn this data into a template, we can use the
functions tfn or dtfn.
tfn is short for template function and will create a function which,
when passed a map, will fill in the template with the values in the
map and return a string of HTML which can be added to the DOM. Use
this when you don't need to update the template after it has been
added to the DOM.
dtfn is short for dynamic template function and will create a
template which can be updated even after it has been added to the
DOM. dtfn takes two arguments, the sequence of nodes and a set of
fields static fields. Static fields can be set once when the template
is first added to the DOM, but they cannot be changed later. In the
example above we would like for the ids to be fields that we set but
do want them to change later so we mark them as static fields.
When slicing templates, it can be helpful to confirm that they work
form the REPL before trying to use them in your application. In the
tutorial-client.html-templates namespace, try some of the following:
Create the template map.
(def t (tutorial-client-templates))Run the dynamic template function.
(def tf (:other-counter t))
(tf)which returns
[{:counter-id [{:id G__1866, :type :content}],
:count [{:id G__1865, :type :content}]}
#<html_templates$fn__1857$fn__1858 tutorial_client.html_templates$fn__1857$fn__1858@5669e732>]Get the template constructor function and create the initial template with an id value of 42.
(let [[_ ctor] (tf)]
(ctor {:id 42}))which returns
<div id="42" class="counter-row">
<span class="counter-label">Counter for <span id="G__1878"></span>:</span>
<span id="G__1877" class="counter"></span>
</div>Dynamic templates are hard to work with manually. In the rendering section we will see that we don't have to do much on this manual manipulation in practice.
Please note that any time we make changes to the namespace
tutorial-client.html-templates the server will have to be restarted
of this code reloaded in order for the changes to take effect.
In the next step we will write the rendering code which allows our application to use these templates.
The tag for this step is v2.0.10.