From Xano Documentation
Jump to: navigation, search

Template Engine

Xano leverages a very powerful template engine. This engine includes a flexible templating language, tight integration with the Xano platform (eg. pages, layouts, macros, modules, and even files), and a renderer which can process templates and output a finished result.

Language

A templating language provides a clear separation between your frontend and backend application layers. This means you can safely make changes to your HTML, Javascript, and CSS files without the worry of having to tiptoe around any complex backend source code. This becomes extremely important when the size of your team grows and you have multiple people working on the same project. Keeping layers isolated from each other, while still providing flexibility is critical to product stability as well as effectiveness of the individuals doing the edits. For example, a designer making a quite template modification shouldn't have to dig through PHP source code.

Syntax

The templating language relies on three syntax formats.

{{ }}: used to print the result of an expression evaluation.
{% %}: used to execute statements.
{# #}: used for comments.

Variables

Variables can be created on the fly. They can be simple constants or lists.

{% set test = 'hello there' %}: assigning a string to the variable test.
{% set test = ['hello', 'there'] %}: assigning an array of two strings to the variable test.
{% set test = 1..10 %}: assigning an array of numbers (using the range syntax) to the variable test.
{% set test = {'hello': 'there'} %}: assigning an associative array to the variable test.

Escaping

By default all expressions are automatically escaped as an HTML attribute. This prevents injection attacks based on user input.

{% set userInput = '<span title=faketitle onmouseover=alert(/ZF2!/);>' %}
{{ userInput }}
outputs
&lt;span&#x20;title&#x3D;faketitle&#x20;onmouseover&#x3D;alert&#x28;&#x2F;ZF2&#x21;&#x2F;&#x29;&#x3B;&gt;

Different types of escaping are described in the filters section below, including the ability to disable escaping.

Tests

Tests are built language constructs that allow you to perform simple tests on expressions. They are commonly used with conditionals.

constant

this test checks if a variable has the exact same value as a constant.
{% if post.status is constant('Post::PUBLISHED') %}
    the status attribute is exactly the same as Post::PUBLISHED
{% endif %}

defined

this test checks if a variable is defined in the current context.
{# defined works with variable names #}
{% if foo is defined %}
    foo is defined
{% endif %}

{# and attributes on variables names #}
{% if foo.bar is defined %}
    foo.bar is defined
{% endif %}

{% if foo['bar'] is defined %}
    foo['bar'] is defined
{% endif %}

empty

this test checks if a variable is empty.
{# evaluates to true if the foo variable is null, false, an empty array, or the empty string #}
{% if foo is empty %}
    foo is empty
{% endif %}

even

this test returns true if the given number is even.
{{ var is even }}

odd

this test returns true if the given number is odd.
{{ var is odd }}

null

this test returns true if the variable is null.
{{ var is null }}

divisibleby

this test checks if a variable is divisible by a number.
{% if loop.index is divisible by(3) %}
    loop.index is divisible by 3
{% endif %}

Conditionals

Conditionals allow the ability to do a comparison and then execute a block of code depending on the result of that comparison. Common conditionals are if statements. If statements can be combined with elseif and else statements.

{% if number is odd %}
  your lucky number is odd!
{% else %}
  your lucky number is even!
{% endif %}{% set luckyNumber = random(2) %}

You can also rely on ternary operators for shorter syntax.

{% set luckyNumber = random(2) %}
{{ 'your lucky number is ' ~ (luckyNumber is odd ? 'odd' : 'even') }}

Loops

Loops provide a way to iterate over arrays and execute the same block of code multiple times.

Iterating over array keys
<h1>Members</h1>
<ul>
    {% for key in users|keys %}
        <li>{{ key }}</li>
    {% endfor %}
</ul>
Iterating over Keys and Values
<h1>Members</h1>
<ul>
    {% for key, user in users %}
        <li>{{ key }}: {{ user.username }}</li>
    {% endfor %}
</ul>
Adding a condition
<ul>
    {% for user in users if user.active %}
      <li>{{ user.username }}</li>
    {% endfor %}
</ul>
The else Clause
<ul>
    {% for user in users %}
        <li>{{ user.username }}</li>
    {% else %}
        <li><em>no user found</em></li>
    {% endfor %}
</ul>
The loop variable

The loop variable is a special variable that is only available within the loop. If there are loops nested within each other, then the loop.parent variable comes in handy.

loop.index: the current iteration of the loop. (1 indexed)
loop.index0: the current iteration of the loop. (0 indexed)
loop.revindex: the number of iterations from the end of the loop (1 indexed)
loop.revindex0: the number of iterations from the end of the loop (0 indexed)
loop.first: true if first iteration
loop.last: true if last iteration
loop.length: the number of items in the sequence
loop.parent: the parent context

Filters

Filters are essentially functions that transform values. They provide a flexible syntax that provides support for easy chaining.

Function example
{{ lower(upper(lower(upper("Welcome to my Website")))) }}
Filter example
{{ "Welcome to my Website"|upper|lower|upper|lower }}

As you can see the filter example provides a much more flexible syntax. There is an implied parameter being applied to each filter and that is the value of the expression to the left of the | character.

html

this filter escapes a string for safe insertion into the final output of an html context and then marks the expression as safe in order to avoid additional auto-escaping.
My username is {{ username|html }}.

js

this filter escapes a string for safe insertion into the final output of a javascript context and then marks the expression as safe in order to avoid additional auto-escaping.
<script>
  var username = '{{ username|js }}';

  alert('My username is ' + username + '.');
</script>

json

this filter escapes a string for safe insertion into the final output of a json context and then marks the expression as safe in order to avoid additional auto-escaping.
{
 "username": "{{ username|json }}"
}

css

this filter escapes a string for safe insertion into the final output of a css context and then marks the expression as safe in order to avoid additional auto-escaping.
<style>
.myBackground {
  background: url('{{ myImageUrl|css }}');
}
</style>

attr

this filter escapes a string for safe insertion into the final output of an html attribute context and then marks the expression as safe in order to avoid additional auto-escaping.
<a href="{{ myClickUrl|attr }}">click here</a>

url

this filter escapes a string for safe insertion into the final output of a parameter name/value of a URL context and then marks the expression as safe in order to avoid additional auto-escaping.
 http://example.com/?username={{ myUsername|url }}

raw

this filter marks the value as being "safe", which means that this variable will not be escaped if raw is the last filter applied to it.
{{ var|raw }} {# var won't be escaped #}

lower

this filter converts a value to lowercase.
{{ 'WELCOME'|lower }}

{# outputs 'welcome' #}

upper

this filter converts a value to uppercase.
{{ 'WELCOME'|upper }}

{# outputs 'WELCOME' #}

trim

this filter strips whitespace (or other characters) from the beginning and end of a string.
{{ '  How are you today.  '|trim }}

{# outputs 'How are you today.' #}

first

this filter returns the first "element" of a sequence, a mapping, or a string.
{{ [1, 2, 3, 4]|first }}
{# outputs 1 #}

{{ { a: 1, b: 2, c: 3, d: 4 }|first }}
{# outputs 1 #}

{{ '1234'|first }}
{# outputs 1 #}

last

this filter returns the last "element" of a sequence, a mapping, or a string.
{{ [1, 2, 3, 4]|last }}
{# outputs 4 #}

{{ { a: 1, b: 2, c: 3, d: 4 }|last }}
{# outputs 4 #}

{{ '1234'|last }}
{# outputs 4 #}

keys

this filter returns the keys of an array. It is useful when you want to iterate over the keys of an array.
{% for key in array|keys %}
  {{ key }}
{% endfor %}

length

this filter returns the number of items of a sequence or mapping, or the length of a string.
{% if users|length > 0 %}
  Hello users!
{% endif %}

format

this filter formats a given string by replacing the placeholders (placeholders follows the sprintf notation).
{{ "I like %s and %s."|format(foo, "bar") }}

{# outputs I like foo and bar
   if the foo parameter equals to the foo string. #}
  

number_format

this filter formats numbers.
{{ 9800.333|number_format(2, '.', ',') }}

{# outputs 9,800.33 #}

nl2br

this filter inserts HTML line breaks before all newlines in a string.
{{ "I like Twig.\nYou will like it too."|nl2br }}
{# outputs

    I like Twig.<br />
    You will like it too.

#}

addArg

this filter adds an parameter with proper escaping to a URL.
{{ 'http://example.com/'|addArg('thankyou') }}

{# outputs http://example.com/?thankyou #}

{{ 'http://example.com/?loc=CA'|addArg('q', 'fast cars') }}

{# outputs http://example.com/?loc=CA&q=fast%20cars #}

date

this filter formats a date to a given format.
{{ post.published_at|date("m/d/Y") }}
{{ "now"|date("m/d/Y") }}

merge

this filter merges an array with another array.
{% set values = [1, 2] %}

{% set values = values|merge(['apple', 'orange']) %}

{# values now contains [1, 2, 'apple', 'orange'] #}

join

this filter returns a string which is the concatenation of the items of a sequence.
{{ [1, 2, 3]|join('|') }}
{# outputs 1|2|3 #}

split

this filter splits a string by the given delimiter and returns a list of strings.
{{ "one,two,three"|split(',') }}
{# returns ['one', 'two', 'three'] #}

striptags

this filter strips SGML/XML tags and replace adjacent whitespace by one space.
{{ some_html|striptags }}

sort

this filter sorts an array.
{% for user in users|sort %}
  {{ user }}
{% endfor %}

anchor

this filter cleans up the string value so that it only consits of letters, numbers, and underscores. This was originally intended to be used to create anchor tags within a link element, although it can easily be used for anything that needs a restricted character set for certain values.
{{ "Hello, this is GREAT!!"|anchor }}
{# outputs Hello_this_is_GREAT #}

Functions

date

this function converts an argument to a date to allow date comparison.
{% if date(user.created_at) < date('-2days') %}
    {# do something #}
{% endif %}

{% if date(user.created_at) < date('-2days', 'Europe/Paris') %}
    {# do something #}
{% endif %}

{% if date(user.created_at) < date() %}
    {# always! #}
{% endif %}

dump

this function dumps information about a template variable. This is mostly useful to debug a template that does not behave as expected by introspecting its variables.
{{ dump(user) }}

random

this function returns a random value depending on the supplied parameter type.
{{ random(['apple', 'orange', 'citrus']) }} {# example output: orange #}
{{ random('ABC') }}                         {# example output: C #}
{{ random() }}                              {# example output: 15386094 (works as the native PHP mt_rand function) #}
{{ random(5) }}                             {# example output: 3 #}

min

this function returns the lowest value of a sequence or a set of values.
{{ min({2: "two", 1: "one", 3: "three", 5: "five", 4: "for"}) }}
{# return "five" #}

max

this function returns the biggest value of a sequence or a set of values.
{{ max({2: "two", 1: "one", 3: "three", 5: "five", 4: "for"}) }}
{# return "two" #}

block

this function allows you to print a block within a template multiple times.
<title>{% block title %}{% endblock %}</title>

<h1>{{ block('title') }}</h1>

{% block body %}{% endblock %}

cycle

this function cycles on an array of values.
{% set fruits = ['apple', 'orange', 'citrus'] %}

{% for i in 0..10 %}
    {{ cycle(fruits, i) }}
{% endfor %}

Tags

load

this tag allows pages, layouts, and macros the ability to reference each other.
Example - utilities.macro
{% macro displayQuote() %}
  Greetings and salutations!
{% endmacro %}
Example - index.page
{% load "utilities.macro" %}

{{ utilities.displayQuote() }}
Example - output
Greetings and salutations!

set

this tag provides support for creating variables. Refer to the variables section for examples of its usage.

block

this tag lays the groundwork for how layouts are used. Refer to the layouts section for examples of its usage.

extends

this tag is used within pages to extend a layout. Refer to the layouts section for examples of its usage.

if

this tag is used for providing support for conditional statements. Refer to the conditionals section for examples of its usage.

for

this tag is used for providing loop support. Refer to the loops section for examples of its usage.

Data Requirements

Data requirements are tightly integrated into the templating language. Each page has the ability to have multiple data requirements assigned to it. When the page gets rendered, all its data requirements get executed and their output gets passed into the templating engine. When the page is processed by the templating engine, the page can access the output of these data requirements through the templating language.

Output from Data Requirement in Object Format

Here we have an example of a data requirement that generates a user list. This example is only showing the output of the data requirement in array form.

[
  'items': [
    [
      'id': '1',
      'username': 'Seanster',
      'email': 'seanster@example.com'
    ],
    [
      'id': '2',
      'username': 'Jackster',
      'email': 'jackster@example.com'
    ],
    [
      'id': '3',
      'username': 'Adna',
      'email': 'adna@example.com'
    ],
  ]
]
Flattened Key/Value Pairs Accessible by Templating Language

This output gets passed into the templating engine. It can then be referenced directly through the templating language. Let's assume we name this data requirement 'userlist'. The following flattened key/value pairs would be accessible.

DATA.userlist.output.items.0.id: 1
DATA.userlist.output.items.0.username: Seanster
DATA.userlist.output.items.0.email: seanster@examplke.com
DATA.userlist.output.items.1.id: 2
DATA.userlist.output.items.1.username: Jackster
DATA.userlist.output.items.1.email: jackster@example.com
DATA.userlist.output.items.2.id: 3
DATA.userlist.output.items.2.username: Adna
DATA.userlist.output.items.2.email: adna@example.com
Template Code

Now using the template language we can iterate through the userlist.

<h1>Userlist</h1>
{% for user in DATA.userlist.output.items %}
  <p>User: id={{ user.id }}, username={{ user.username }}, email={{ user.email }}</p>
{% endfor %}
Output

The following output was generated by the templating engine by processing the template code.

<h1>Userlist</h1>
<p>User: id=1, username=Seanster, email=seanster@example.com</p>
<p>User: id=2, username=Jackster, email=jackster@example.com</p>
<p>User: id=3, username=Adna, email=adna@example.com</p>

Globals

Globals are special variables that are always accessible... even inside a macro.

The Xano platform exposes certain functionality through the "xano" global. This global supports multiple interfaces to different aspects of Xano through sub-namespaces.

xano.file.getUrl

This function creates an externally accessible URL to a file resource that belongs to the applicable site.

{{ xano.file.getUrl({name: 'main.js') }}

{# outputs http://example.com/m/r/static/44/32/main.js #}

Files have the ability to be run through several processing engines to perform adjustments on them. If you ever want to bypass the processors, you can do that with the following.

{{ xano.file.getUrl({name: 'main.js', processor: 'off') }}

xano.file.compile

This function registers a file resource to be included in the static resource compilation. Several compile functions are common along with a following call to the getCompiledUrl function.

{{ xano.file.compile({src: 'main.js', label: 'js') }}

Files have the ability to be run through several processing engines to perform adjustments on them. If you ever want to bypass the processors, you can do that with the following.

{{ xano.file.compile({src: 'main.js', label: 'js', processor: 'off') }}

xano.file.getCompiledUrl

This function creates an externally accessible URL to the result of multiple file resources being compiled together for minification and obfuscation.

{{ xano.file.getCompiledUrl({dst: 'admin.js', label: 'js') }}

{# outputs http://example.com/m/r/compiled/2b423432/9942bc90df/admin.js #}

xano.module.render

This function renders a module page which can then be embedded into the page that is calling this function. This provides the ability to render multiple modules within a parent page.

{% load xano.module.render({page: 'myModulePageName', module: 'myModuleName'}) %}

New technology to bridge the gap between simplicity and flexibility.