Skip to main content

Template syntax

Falu Templates use a very simple, yet very powerful, engine with its roots with Mustache, but includes a few advanced features that make it great for authoring plain text messages.

Here's everything you need to know about the engine.

Variable Interpolation

"Variable Interpolation" is the heart and soul of any templating engine.

If you have a template model like this (represented as JSON):

{
"user": {
"name": "John"
}
}

And this template:

Welcome home {{ user.name }}

Falu will produce combine the two and produce:

Welcome home John

If you have used Mustache.js, this should be very familiar. But Falu has a few more capabilities that make writing templates a breeze.

Scoping

Sometimes we'll have more complex models, and so scoping to a particular property will make the markup easier to read:

{{#user}}
Welcome home {{ name }}
{{/user}}

Notice that if we're building a section of the template that uses multiple properties from user, we do not need to keep repeating user. with each variable interpolation.

Collection Handling

Let's say we have this more complicated model:

{
"name": "John Kamau",
"vehicles": [
{
"registration": "123 KL 3"
},
{
"registration": "054F 87T"
}
]
}

And this template:

{{ name }} vehicles:
{{#each vehicles}}
{{ registration }}
{{/each}}

Falu will combine these to produce:

John Kamau vehicles:
123 KL 3
054F 87T

Advanced Interpolation

If we've scoped out template to a property of a model, we may want to "reach up" to a property in the outer scope. For example, let's say we wanted to change the content from the Collection Handling example above to look like this:

123 KL 3 is owned by: John Kamau
054F 87T is owned by: John Kamau

We can use special interpolation syntax to do this without needing to repeat the values in our template model:

{{#each vehicles}}
{{ name }} is owned by: {{../../name}}
{{/each}}

Note the ../ in the template, which just means "go up one level" in my template model and look for the property name that follows. You can go up as many levels in you model as needed by repeating ../ multiple times at the start of you {{ ... }} section.

Advanced Value Handling

Falu is permissive about missing values in your models. If you scope to a property that does not exist, Falu will skip that section. In this way, you can build templates that do not require if/else logic.

Consider the following model:

{
"name": "John Kamau",
"vehicles": [
{
"registration": "123 KL 3",
"country": "Kenya"
},
{
"registration": "054F 87T"
}
]
}

Let us couple it with this template:

{{#each vehicles}}
{{name}} is owned by: {{../../name}}
{{#country}} in {{.}}{{/country}}
{{/each}}

After combining, we will produce the following:

123 KL 3 is owned by: John Kamau in Kenya
054F 87T is owned by: John Kamau

Note that because 054F 87T does not have a country property, "in " is omitted from the output. Also note that we can use . in the Variable Interpolation to reference the model object in the {{#country}} scoped block.

Inverted Groups (or, how to make Placeholders)

Falu will skip anything in a template that references a value that is null, false, or empty (such as an array that has no elements). However, sometimes it's useful to include content specifically when a value is absent from the model, and, of course, Falu supports this using "Inverted Groups".

Let us consider this template:

{{#each vehicles}}
{{name}} is owned by: {{../../name}}
{{#country}} in {{.}}{{/country}}
{{^registered}} (unknown date){{/registered}}
{{/each}}

If registered is not specified in out template model, unknown date will be rendered.

Given the data:

{
"name": "John Kamau",
"vehicles": [
{
"registration": "123 KL 3",
"country": "Kenya",
"registered": "16 June 2020"
},
{
"registration": "054F 87T",
"country": "Kenya",
}
]
}

After combining, we will produce the following:

123 KL 3 is owned by: John Kamau in Kenya
054F 87T is owned by: John Kamau (unknown date)

Inverted Groups are a powerful way to provide placeholder text when information is not available, or not applicable.