Skip to main content

Template Reference

Complete reference for the mylekha_template_engine template language — syntax, all built-in tags, all built-in filters, and common patterns.

Template Syntax

Variable output

{{ variable }}
{{ object.property }}
{{ list.0 }}
{{ "string literal" }}
{{ 42 }}
{{ true }}

Nested access uses . for both Map keys and List indices:

{{ sale.items.0.name }}
{{ address.zip }}

Filter application

{{ variable | filterName }}
{{ variable | filterName: arg1, arg2 }}
{{ variable | filter1 | filter2: arg }}

Tag blocks

{% tagName args %}
content
{% endtagName %}

Whitespace control

Prefix or suffix with - to trim the adjacent whitespace/newline:

{{- variable }}    ← trims whitespace before the output
{{ variable -}} ← trims whitespace after the output
{%- tag %} ← trims whitespace before the tag
{% tag -%} ← trims whitespace after the tag

Object and array literals

{% assign point = { x: 10, y: 20 } %}
{% assign colors = ["red", "green", "blue"] %}

as capture keyword

Any block tag can redirect its rendered output into a variable instead of emitting it:

{% filter upper as heading %}my title{% endfilter %}
<h1>{{ heading }}</h1>

Built-in Tags

assign

Creates a variable scoped to the block. The RHS is a full filter expression.

{% assign subtotal = price | multi: quantity %}
Total: {{ subtotal }}
{% endassign %}
note

subtotal reverts to its previous value after {% endassign %}. Use {% capture %} if you need the variable outside the block.


capture

Renders the inner content and stores it as a string in the current context scope.

{% capture invoice_header %}
<h1>Invoice #{{ order.number }}</h1>
{% endcapture %}

{{ invoice_header }} ← available throughout the current template

cache

Same as capture, but stores the result at the root context scope — visible across all child contexts including {% include %} partials.

{% cache site_name %}Mylekha POS{% endcache %}

comment

Discards all inner content. Nothing is rendered.

{% comment %}
TODO: add tax calculation
{{ price | multi: 1.1 }}
{% endcomment %}

cycle

On each invocation, advances to the next value in the list (wraps around).

{% for item in items %}
<tr class="{% cycle "odd", "even" %}">
<td>{{ item.name }}</td>
</tr>
{% endfor %}

extends

Inherits from a base template. Must be the first tag in the file. Uses {% block %} to override named sections.

child.html

{% extends "base.html" %}

{% block title %}Order Receipt{% endblock %}

{% block content %}
<p>Order {{ order.number }}</p>
{% endblock %}

base.html

<!DOCTYPE html>
<html>
<head><title>{% block title %}Default Title{% endblock %}</title></head>
<body>{% block content %}{% endblock %}</body>
</html>

The path can also be a variable:

{% extends template_path %}

filter tag

Applies a filter (or chain of filters) to the entire rendered output of the block.

{% filter upper %}
hello world
{% endfilter %}

Output: HELLO WORLD

Chainable:

{% filter capfirst | replace: "old", "new" %}content{% endfilter %}

for

Iterates over a collection. Supports {% else %} or {% empty %} for the empty-collection case.

{% for item in order.items %}
{{ forloop.counter }}. {{ item.name }}
{% else %}
No items.
{% endfor %}

The collection expression supports filters:

{% for item in items | reversed %}
{% for i in count | generateList %}

forloop Variable

Inside a {% for %} block, a forloop map is available:

KeyTypeDescription
counter / indexint1-based position
counter0 / index0int0-based position
revcounter / rindexintReverse 1-based position
revcounter0 / rindex0intReverse 0-based position
firstbooltrue on the first iteration
lastbooltrue on the last iteration
lengthintTotal number of items
nameString"$itemVar-$collectionExpr"
parentloopMapThe forloop of the enclosing {% for %}
{% for item in items %}
{% if forloop.first %}<ul>{% endif %}
<li>{{ forloop.counter }}. {{ item.name }}</li>
{% if forloop.last %}</ul>{% endif %}
{% endfor %}

if / unless

{% if condition %}
...
{% elseif other %}
...
{% else %}
...
{% endif %}

unless negates the initial condition:

{% unless user.active %}Please log in.{% endunless %}

Supported operators:

OperatorExample
=={% if status == "active" %}
!={% if count != 0 %}
>, <, >=, <={% if total > 100 %}
and{% if a and b %}
or{% if a or b %}
not{% if not user.active %}
contains{% if list contains item %}
in{% if item in list %}

ifchanged

Renders the inner content only when the output differs from the previous render of this same tag instance. Useful for group headers inside loops.

{% for item in items %}
{% ifchanged %}{{ item.category }}{% endifchanged %}
<p>{{ item.name }}</p>
{% endfor %}

include

Embeds another template, resolved via the Root provided to the parent template's Source.

{% include "partials/header.html" %}

Inject variables into the partial scope:

{% include "partials/item_row.html" with item=current_item label="SKU" %}

only clears all parent variables — only the with assignments are visible in the partial:

{% include "partials/clean.html" with title=page_title only %}
warning

Requires a Root — see Troubleshooting.


load

Activates a named module at render time, registering its filters and tags into the context.

{% load mymodule %}

The module must already be registered before parsing:

context.modules['mymodule'] = MyModule();

block

Defines a named region that child templates can override via {% extends %}.

{% block sidebar %}
Default sidebar content
{% endblock %}

regroup

Groups a List<Map> by the value of a field. Stores the result in a new variable as a list of {grouper, list} maps.

{% regroup cities by country to country_list %}

{% for group in country_list %}
<h3>{{ group.grouper }}</h3>
<ul>
{% for city in group.list %}
<li>{{ city.name }}</li>
{% endfor %}
</ul>
{% endfor %}

Built-in Filters

String

FilterArgsDescription
upper / upcaseConvert to uppercase
lower / downcaseConvert to lowercase
capfirst / capitalizeCapitalize first character
joinseparator? (default ' ')Join iterable to string
reversedReverse a string (char-by-char) or list
sizeLength of String/Iterable; 0 otherwise
isEmptytrue if null, empty string, or empty iterable
isNotEmptyNegation of isEmpty
defaultfallbackReturns input.toString() if non-empty, else first non-empty arg
default_if_nonefallbackReturns input if non-null, else first non-null arg
{{ product.name | upper }}
{{ tags | join: ", " }}
{{ description | default: "No description" }}

Numeric Conversion

FilterArgsDescription
parseIntConvert to int
parseDoubleConvert to double
parseNumConvert String/num to num
absAbsolute value
roundDoubleplaces? (default 2)Round to N decimal places
stringAsFixedplaces? (default 0)Fixed-decimal string representation
{{ "42.7" | parseInt }}        → 42
{{ value | roundDouble: 2 }} → 42.70
{{ price | stringAsFixed: 0 }} → 43

Arithmetic

FilterArgsDescription
addnAdds n to a num; concatenates two lists
minusnSubtracts n from num
multinMultiplies num by n
dividenDivides num by n
modulusnnum % n
{{ price | multi: quantity }}
{{ total | add: tax }}
{{ index | modulus: 2 }}

Mutating Filters

These filters mutate a Map{value: num} in place and return null (no output). Use them alongside self_add for mutable counters.

FilterArgsDescription
self_addnmap['value'] += n
self_minusnmap['value'] -= n
self_multinmap['value'] *= n
self_dividenmap['value'] /= n
{% assign counter = { value: 0 } %}
{% for item in items %}
{{ counter | self_add: 1 }} ← no output, mutates counter
{{ counter.value }} ← outputs current count
{% endfor %}

Formatting

FilterArgsDescription
date / date_formatformat?Format a DateTime or ISO string. Default: 'EEEE, d/MMM/y hh:mm'
number_formatpattern?Format as NumberFormat in en_US. Default: "###,###,###.00"
moneyFormatplaces, sign?, isSuffix?Fixed decimal with optional currency sign prefix (isSuffix=0) or suffix (isSuffix=1)
{{ order.created_at | date: "d MMM y" }}
{{ total | number_format: "###,###.00" }}
{{ price | moneyFormat: 2, "USD", 0 }} → USD 49.99
{{ price | moneyFormat: 2, "KHR", 1 }} → 49.99KHR

Collection

FilterArgsDescription
getkeyReturns map[key]
elementAtindexGets item at index from string, list, iterable, or map values
generateListFrom integer n, generates [0, 1, ..., n-1]
mapOfkey?Maps List<Map> to a list of map[key] values
whereOfkey, op, valueFilters List<Map> where map[key] op value. Ops: ==, =, >, >=, <, <=
foldOfkey, op, initialFolds a numeric field in List<Map>. Ops: +, -, *, /, %
{{ items | generateList }}                         → [0, 1, 2, ...]
{{ items | mapOf: "name" }} → ["Alpha", "Beta", ...]
{{ items | whereOf: "active", "==", true }} → filtered list
{{ items | foldOf: "price", "+", 0 }} → sum of prices

Content

FilterArgsDescription
markdownToHtmlConverts Markdown input to HTML (trailing newlines stripped)
{{ product.description | markdownToHtml }}

Barcode / QR

FilterArgsDescription
qrcodewidth?, height?, type?, fontSize?Renders a barcode as data:image/png;base64,...

Defaults: width=300, height=120, type="Code128", fontSize=48
Font sizes: 14arial14, 24arial24, 48arial48

<img src="{{ item.barcode | qrcode: 300, 120, 'Code128', 14 }}" />
<img src="{{ product.code | qrcode: 300, 300, 'qrcode' }}" />

Localization

FilterArgsDescription
tr...argsTranslate a key using LocalizationService. Supports positional args and plural forms.
{{ "welcome" | tr }}
{{ "greeting" | tr: user.name }}
{{ "item_count" | tr: count }}

See Localization for full setup and plural rules.