This is an overview of our available templating features. 

We have used Moz://as Templating-Language Nunjucks, which has support for a lot of common javascript- and templating features. We have enriched it with a lot of other useful features:

Variables

A variable looks up a value from the project's context. If you simply wanted to display one variable, you would do:

#{ variable }#

#{ model.name }#
#{ model["name"] }#

This looks up model.name from the context and displays it. Variable names can have dots in them which lookup properties, just like javascript. You can also use the square bracket syntax. These two forms to the exact same thing, just like javascript.

If a value is undefined or null, the engine stops and shows the occured error. The same behavior occurs when referencing undefined or null objects.

Filters

Filters are essentially functions that can be applied to the variables. They are called with the pipe operator | and optionally take arguments.

#{ model.name | camelCase }#
#{ model.name | join(",") }#
#{ model.name | replace("foo", "bar") | upper }#

To learn the basic Filters scroll further to the "Builtin Filters" or the "Global Functions". If you want to learn more about the casing of variables, take a look here

If

The "IF" tests a condition and lets you selectively run code-content. It behaves exactly as javascript's if behaves.

<{ if check }> this is the true result <{ endif }>

If a variable is defined and evaluates to true, the inner code will be displayed. Otherwise, nothing will be shown. You can specify alternate conditions with "elif" (or "elseif", which is simply an alias of "elif") and "else"
 

<{ if property.type.isStandard }>
  #{ model.name | lower }#;
<{ elif property.type.isForeign }>
  #{ model.name | lower }#Fk
<{ else }>
  #{ model.name | lower }#Object;
<{ endif }>


Similar to javascript's ternary operator, you can use if as if it were an inline expression:

#{ "true-variable" if check else "false-variable" }#


The above outputs the string "true" if foo is truthy, otherwise "false". Unlike javascript's ternary operator, the else is optional:

#{ "true-variable" if check }#

Comparisons and Logic

You can use the following operators to compare two values:

  • ==
  • ===
  • !=
  • !==
  • >
  • >=
  • <
  • <=

If you want to combine different expressions, you can use the following Operators.
Also use parentheses to group expressions:

  • and
  • or
  • not

Examples:

<{ if model.propertys.length < 5 }>
  ...
<{ endif }>

<{ if i == 0 }>
  ...
<{ endif }>

<{ if model.propertys.length > 0 and property.type.isEmbedded }>
  ...
<{ endif }>

<{ if i == 0 and not property.type.isEmbedded }>
  ...
<{ endif }>

<{ if (x < 5 or y < 5) and foo }>
  ...
<{ endif }>

For

The "FOR" iterates over arrays and dictionaries. The above example lists all the propertys using the name attribute of each item in the model.propertys array. If the propertys array was empty, the contents of the optional else clause would instead be rendered.

<{ for property in model.propertys }>
  #{ property.name }#
<{ else }>
  This would display if the 'model.propertys' collection were empty
<{ endfor }>


Inside loops, you have access to a few special variables:

  • loop.index: the current iteration of the loop (1 indexed)
  • loop.index0: the current iteration of the loop (0 indexed)
  • loop.revindex: number of iterations until the end (1 indexed)
  • loop.revindex0: number of iterations until the end (0 based)
  • loop.first: boolean indicating the first iteration
  • loop.last: boolean indicating the last iteration
  • loop.length: total number of items

Protected Areas

Using our template syntax, you can specify the protected area in your source code for any language. 

<< #{model.name | hyphen}#-do-my-stuff >>

<< [/***] code [***/] >>


results in:


/* << item-do-my-stuff    */
/*    item-do-my-stuff >> */

/*** << code    ***/
/***    code >> ***/

Using Protected Areas allows you to add custom code whilst enhancing your project: Change your template code or your Front- and Backend-Graph and regenerate your project as many times as necessary - you don't have to worry about your custom code.

Set

The "Set" lets you create or modify a variable. You can set existing ones, or introduce new variables (or even set multiple variables at once)

#{ model.name }#    // outputs "james green"
<{ set model.name = "mark jordan" }>
#{ model.name }#    // will be "mark jordan"
<{ set x, y, z = 5 }>

If set is used at the top-level, it changes the value of the global template context.

Expressions

You can use many types of literal expressions that you are used to in javascript.

  • Strings: "How are you?", 'How are you?'
  • Numbers: 40, 30.123
  • Arrays: [1, 2, "array"]
  • Dicts: { one: 1, two: 2 }
  • Boolean: true, false

Builtin Filters

filter 

You can use the filter-pipe to select only components of your lists, to which the applied filter is valid. You can search for different conditions: one the one hand side you can check if a value is present. You can access nested informations through dots (.). One the other side you can check for values.

<{ for property in model.propertys | filter("type.model")}>
<{ endfor }>

or

<{ for model in project.models | filter("modelType", "Entity")}>
<{ endfor }>

find 

You could also search or one component of your lists like this.

<{ set userEntity = project.models | find("name", "User")}>

order 

Another possibility is to order your components in your lists in the following manner:

<{ for model in project.models | order("name")}>

dependencys 

You can access all the relationed models (dependencys) through the dependency-filter. In the standard way the pipe checks the information-tree into two levels. But you could also define your own level of depth.

<{ for dependency in project.models | dependency }>

or

<{ for dependency in project.models | dependency(2) }>

roots 

This pipe filters for only these models, which are not embedded in other entities, so exist on their own (so called "roots").

<{ for dependency in project.models | roots }>

embeds 

This pipe filters for only the relationed models, which are connected by the Embedded-Relation.

<{ for model in project.models | embeds }>
...

foreigns 

This pipe filters for only the relationed models, which are connected by the Foreign-Relation.

<{ for model in project.models | foreigns }>
...

groupby

Group a sequence of objects by a common attribute:

<{ set items = [ 
  { name: 'james', type: 'green' },
  { name: 'john', type: 'blue' },
  { name: 'jim', type: 'blue' },
  { name: 'jessie', type: 'green' }
]}>

<{ for type, items in items | groupby("type") }>
  #{ type }#:
  <{ for item in items }>
    #{ item.name }#
  <{ endfor }>
<{ endfor }>

selectattr (only the single-argument form)

Filter a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding.

This is the opposite to rejectattr.

If no test is specified, the attribute’s value will be evaluated as a boolean.

<{ set foods = [{tasty: true}, {tasty: false}, {tasty: true}] }>

#{ foods | selectattr("tasty") | length }#=>2

rejectattr (only the single-argument form)

Filter a sequence of objects by applying a test to the specified attribute of each object, and rejecting the objects with the test succeeding.

This is the opposite of selectattr filter.

If no test is specified, the attribute’s value will be evaluated as a boolean.

<{ set foods = [{tasty: true}, {tasty: false}, {tasty: true}]}>

#{ foods | rejectattr("tasty") | length }#

default(value, default, [boolean])

If value is  undefined, return default, otherwise value. If boolean is true, any JavaScript falsy value will return default (false, "", etc)

dump

Call JSON.stringify on an object and dump the result into the template. Useful for debugging: #{ items | dump }#.

<{ set items = ["a", 1, { b : true}] }>
#{ items | dump }#
=>
["a",1,{"b":true}]
Dump provides the spaces parameter to add spaces or tabs to the resulting values. This makes the results more readable

first

Get the first item in an array or the first letter if it's a string:

<{ set items = [1,2,3] }>
#{ items | first }#
=> 1

<{ set word = 'abc'}>
#{ word | first }#
=> 1

last

Get the last item in an array or the last letter if it's a string:

<{ set items = [1,2,3] }>
#{ items | last }#
=> 3
<{ set word = 'abc' }>
#{ word | last }#
=> c

random

Select a random value from an array. (This will change everytime the page is refreshed).

#{ [1,2,3,4,5,6,7,8,9] | random }#
=> A random value between 1-9 (inclusive).

wordcount

Count and output the number of words in a string:

<{ set foo = "Hello World"}>
#{ foo | wordcount }#
=> 2

replace

Replace one item with another. The first item is the item to be replaced, the second item is the replaced value.

<{ set numbers = 123456 }>
#{ numbers | replace("4", ".") }#
=> 123.56

<{ set letters = aaabbbccc}>
#{ letters | replace("", ".") }#
=> .a.a.a.b.b.b.c.c.c.  

<{ set letters = "aaabbbccc" }>
#{ letters | replace("a", "x", 2) }#
=> xxabbbccc

<{ set letters = "aaabbbccc" }>
#{ letters | replace("ab", "x", 2) }#
=> aaxbbccc

indent

Indent a string using spaces. Default behaviour is not to indent the first line. Default indentation is 4 spaces.

#{ "one\ntwo\nthree" | indent }#
=> one    two    three      

<{ "one\ntwo\nthree" | indent(6) }>
=> one      two      three 

join

Return a string which is the concatenation of the strings in a sequence:

<{ set items =  [1, 2, 3] }>
#{ items | join }#
=> 123

<{ set items = ['foo', 'bar', 'bear'] }>
#{ items | join(",") }#
=> foo, bar, bear

<{ set items = [ { name: 'foo' }, { name: 'bar' }, { name: 'bear' }]}>
#{ items | join(",", "name") }#
=> foo,bar,bear

batch

Return a list of lists with the given number of items:

<{ set items = [1,2,3,4,5,6] }>
<{ set dash = joiner("-") }>
<{ for item in items | batch(2) }>
#{ dash() }#<{ for items in item }>#{ items }#<{ endfor }>
<{ endfor }>
=> 12-34-56

list

Convert the value into a list. If it was a string the returned list will be a list of characters.

<{ for i in "foobar" | list }>
  #{ i }#,
<{ endfor }>
=> f,o,o,b,a,r,

length

Return the length of an array or string, or the number of keys in an object:

#{ [1,2,3] | length }#
#{ "test" | length }#
#{ {key: value} | length }#

reverse

Reverse a string:

#{ "abcdef" | reverse }#
=> fedcba

<{ for i in [1, 2, 3, 4] | reverse }>
  #{ i }#
<{ endfor }>

slice

Slice an iterator and return a list of lists containing those items:

<{ set arr = [1,2,3,4,5,6,7,8,9] }>
<{ for items in arr | slice(3) }>
  <{ for item in items }>
    #{ item }#
  <{ endfor }>
<{ endfor }>

Global Functions

There are a few builtin global functions that cover some common (or uncommon) cases.

cycler(item1, item2, ...itemN)

An easy way to rotate through several values is to use cycler, which takes any number of arguments and cycles through them.

<{ set cls = cycler("odd", "even") }>
<{ for row in rows }>
  #{ row.name }#
<{ endfor }>

In the above example, odd rows have the class "odd" and even rows have the class "even". You can access the current item on the current property (in the above example, cls.current).

range([start], stop, [step])

If you need to iterate over a fixed set of numbers, range generates the set for you. The numbers begin at start(default 0) and increment by step (default 1) until it reaches stop, not including it.

<{ for i in range(0, 5) }>
  #{ i }#,
<{ endfor }>

joiner([separator])

When combining multiple items, it's common to want to delimit them with something like a comma, but you don't want to output the separator for the first item. The joiner class will output separator (default ",") whenever it is called except for the first time.

<{ set comma = joiner() }>
<{ for tag in tags }>
  #{ comma() }# #{ tag }#
<{ endfor %}

If tags was ["food", "beer", "dessert"], the above example would output food, beer, dessert.

Regular Expressions

A regular expression can be created just like JavaScript, but needs to be prefixed with r:

<{ set regExp = r/^foo.*/g }>
<{ if regExp.test('foo') }> Foo in the house! <{ endif }>

The supported flags are the following. See Regex on MDN for more information.

  • g: apply globally
  • i: case insensitive
  • m: multiline
  • y: sticky

Did this answer your question?