create-modulo
Version:
Starter projects for Modulo.html - Ready for all uses - Markdown-SSG / SSR / API-backed SPA
468 lines (354 loc) • 13.8 kB
HTML
<!DOCTYPE html><meta charset=utf8><script src=../static/Modulo.html></script><script type=md>---
title: Template Tags
---
This document lists and shows examples for each of the the built-in Template
Tags that are already registered with Modulo template system.
# Template Tags
## comment
Used specifically for commenting out blocks of Templating code. Ignores
everything between `{% comment %}` and `{% endcomment %}`. Do not nest comment
tags (e.g. one comment tag cannot contain or comment out another).
An optional note may be inserted in the first tag. This can be useful to
document why the code was commented out or disabled. For example:
`{% comment "Deactivating due to API bug" %}`
An example of a comment tag:
```modulo
edit:demo=modulo
<Template>
{% comment %}
<p>Commented out text that will be ignored
{{ nonExistingVar|brokenFilter:"abc" }}</p>
{% endcomment %}
<p>After comment</p>
</Template>
```
## debugger
Inserts a "debugger" statement at that location in JavaScript. This allows for detailed debugging of the generated code.
In the following demo, you can uncomment the "debugger" statement to practice "stepping through" the for loop, examining the `CTX.user` variable for each iteration in the Developer Tools debug panel.
```modulo
edit:demo=modulo
<Template>
{% for user in state.users %}
<!-- (Hint: try removing the "comment" tags to enable the debugger -->
{% comment %} {% debugger %} {% endcomment %}
<p>{{ user.username }}</p>
{% endfor %}
</Template>
<State
users:='[
{"username": "zer0c00l"},
{"username": "ac1dburn", "id": 1337},
{"username": "the_phantom_phr34k", "name": "Ramon"}
]'
></State>
```
> **Use sparingly** - This is a tag that should be used sparingly outside of
> debugging. It's much better to check for missing values (e.g.
> `{% if not state.val %}...`) and provide alternative behavior than for
> a potentially buggy or partially correct component to continue rendering
> after an error.
## ignoremissing
Ignore missing values (along with _all_ other run-time generated errors).
Usually, when a runtime error occurs, Modulo will allow the exception to stop
the component from rendereing. This tag will fully silence these errors, and
continue rendering the rest of the component (possibly with portions missing).
This tag is useful for debugging, as you can use it to work on one part of
a template at a time as you silence errors in another spot.
```modulo
edit:demo=modulo
<Template>
{% ignoremissing %}
<p>Testing: {{ state.testing|upper }}</p>
<p>Notreal: {{ state.missing|alsomissing }}</p>
{% endignoremissing %}
</Template>
<State
testing="hello world!"
></State>
```
## include
Include another _Templater_, specified by it's name. It's useful for breaking up large and complicated templates into parts that are loaded independently.
```modulo
edit:demo=modulo
<Template -name="other_template">
<p>{{ state.testing }}</p>
</Template>
<Template>
<h1>hello</h1>
{% include other_template %}
</Template>
<State
testing="hello world!"
></State>
```
## for
For-loops are for repeating the same HTML code multiple times. It will repeat a block of templating code for every item in a specified array or object. It's useful for displaying search results, blog articles, chat messages, and much more: Any time you have unknown quantities or _plural_ amounts of data that you want to template on the screen.
At it's core, `{% for %}` will loop over each item in an array, making the item
available in a specified template variable. This is often done to objects in an
array stored in state, such as data that came back from an API. Examine the
following example:
```modulo
edit:demo=modulo
<Template>
<ul>
{% for athlete in state.athletes %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
</Template>
<State
athletes:='[
{"name": "Devante Adams"},
{"name": "Steph Curry"},
{"name": "Megan Rapinoe"}
]'
></State>
```
Note that your for loops should conventionally follow the pattern of `{% for SINGULAR_THING in PLURAL_THINGS %}`. For 3 examples of this: `{% for item in state.item_data %}`, `{% for user in users %}`, or `{% for city in cities %}`.
Within the repeated code of the for loop, then the "singular thing" (the variable defined by the for loop) will be available as a template variable. Typically, the "plural variable" will be an Array or Object defined from the `State` or `Props` CParts. Also, it's worth noting that you can loop over an array in reverse by using the `|reversed` filter, e.g. `{% for obj in list|reversed %}`.
If you need to loop over an _object_, you can unpack each key / value pair into individual variables. For example, if your state contains an array of (x, y) coordinates called `state.data`, you could use the following to output the list of points:
```modulo
edit:demo=modulo
<Template>
<ul>
{% for name, color in state.fave_colors %}
<li><strong>{{ name }}</strong>: {{ color }}</li>
{% endfor %}
</ul>
</Template>
<State
fave_colors:='{
"Devante Adams": "Green",
"Steph Curry": "Golden",
"Megan Rapinoe": "Blue"
}'
></State>
```
## empty
Often you will want to include a default, empty, or "404 message" if nothing is in the array of a `for` tag. To avoid cluttering your loops with extra if-statements, the for tag can take an optional `{% empty %}` clause, which functions identically to an if-statement that executes only if the given data is empty or could not be found (e.g. if 0 iterations of the loop were run). Observe the following example:
```modulo
edit:demo=modulo
<Template>
<ul>
{% for name, color in state.fave_colors %}
<li><strong>{{ name }}</strong>: {{ color }}</li>
{% empty %}
No colors were found.
{% endfor %}
</ul>
</Template>
<State
fave_colors:='{}'
></State>
```
## if
The if-statement allows a block of HTML code to be conditionally included. It allows "branching" in your templates: That is, one or more optional "branches" or blocks of HTML templating code that will be included only if a certain condition is satisfied.
The simplest behavior of the `{% if %}` tag is to evaluate a variable, and if that variable both exists and is a "truthy" value according to JavaScript ([see MDN "Truthy"](https://developer.mozilla.org/en-US/docs/Glossary/Truthy)), the specified block will be included. By default, `if` will include (or not) all code until it encounters an `{% endif %}` tag to close. However, it also supports using an `{% else %}` tag before the `{% endif %}` tag, which can provide alternative code.
Examine the following example, and observe what happens as you change state variables from `true` to `false`, or vice-versa:
```modulo
edit:demo=modulo
<Template>
{% if state.show %}
Hello testing template world!
{% endif %}
</Template>
<State
show:=true
></State>
```
## else
```modulo
edit:demo=modulo
<Template>
{% if state.hello %}
Hello testing template world!
{% else %}
Goodbye testing template world!
{% endif %}
</Template>
<State
hello:=false
></State>
```
## elif, elseif
Like with the `else` tag, the `if` tag may also optionally proceed `{% elif %}`
tags, which is a shortened version of the word "else" and "if", combined into a
single, made-up word "elif". The behavior of the `{% elif %}` is very similar
to the "if": It requires specifying condition which will be evaluated, and it
will only include the specified code block if that condition evaluates to be
true. Unlike the `{% else %}` tag, a single `{% if %}` can has as many `{% elif
%}` tags as you'd like, and it is guaranteed that it will only execute one of
those. In other words, only one `{% if %}`, `{% elif %}`, or `{% else %}` code
block will be executed, and there's never a risk that two "elifs" could get
executed in the same "chain".
For an example of this, examine the following more complicated example:
```modulo
edit:demo=modulo
<Template>
{% if state.athletes %}
Athletes exists. Total athletes: {{ state.athletes|length }}
{% elif state.benched %}
Benched exists. Total benched: {{ state.benched|length }}
{% else %}
No athletes.
{% endif %}
</Template>
<State
benched:='[
{"name": "Steph Curry"}
]'
></State>
```
In the above, if `state.athletes` exists, the number of athletes will be
displayed by the `{{ state.athletes|length }}` filtered template variable.
**Beta note:** `elseif` alias not yet implemented.
## with
With is a highly useful tag to refactor templates that end up getting too
complex with many filters. Adding a `{% with ... %}` lets you "rename" or
"alias" a variable, property, or series of filters as another, shorter variable
name to be used within the tag. In the generated JavaScript code, this value
will be computed once and stored as a variable. See below:
```modulo
edit:demo=modulo
<Template>
{% with state.users|sorted:"username"|reversed|first as user %}
<h4>Last alphabetical user:</h4>
<p>Username: {{ user.username }} - ID #{{ user.id }}</p>
{% endwith %}
</Template>
<State
users:='[
{"username": "zer0c00l", "id": 2600},
{"username": "ac1dburn", "id": 1337},
{"username": "the_phantom_phr34k", "name": "Ramon"}
]'
></State>
```
## if-tag comparison operators
Within the if tag, you can use a variety of "operators". Operators behave similarly to JavaScript operators: They allow comparisons of template variables with other template variables and/or hardcoded values. There are about a dozen built-in operators. As with template-tags, it is also possible to configure your own custom operators.
Built-in operators: `==, >, <, >=, <=, !=, not in, is not, is, in, not, gt, lt`
## Filters (operators)
You can also use filters in combination with operators within an if tag. For example:
```modulo
edit:demo=modulo
<Template>
{% if state.plays|length gt 2 %}
<p>There are more than 2 plays!</p>
{% endif %}
</Template>
<State
plays:='[ "Macbeth", "Hamlet", "Cymbeline" ]'
></State>
```
# Operators
## `==`, `is` (operator)
Check for equality. Note that this will be a "strict" comparison, equivalent to JavaScript's triple-equals `===` operator. The syntax variants `==` and `is` are aliases of each other.
```modulo
edit:demo=modulo
<Template>
{% if state.somevar == "x" %}
This appears if variable somevar equals the string "x"
{% endif %}
</Template>
<State
somevar="x"
></State>
```
## `!=`, `is not` (operator)
Check for inequality. Note that this will be a "strict" comparison, equivalent to JavaScript's triple-not-equals `!==` operator. The syntax variants `!==` and `is not` are aliases of each other.
```modulo
edit:demo=modulo
<Template>
{% if state.somevar != "x" %}
This appears if variable state.somevar does not equal the string "x".
{% endif %}
</Template>
<State
somevar="y"
></State>
```
## `not` (operator)
You can use "not" to invert or negate an "if" tag:
```modulo
edit:demo=modulo
<Template>
{% if not state.show %}
Do not show it!
{% else %}
Show it!
{% endif %}
</Template>
<State
show:=false
></State>
```
## `lt`, `<`, `<=` (operators)
Less than. Has a few variants: `lt` (preferred) and `<` (alternative) will
check to see if a variable is strictly less than a given variable or value,
while `<=` will be "less than or equal to" and thus also allow it if its equal.
Example:
```modulo
edit:demo=modulo
<Template>
{% if state.somevar lt 100 %}
This appears if variable somevar is less than 100.
{% endif %}
</Template>
<State
somevar:=50
></State>
```
## `gt`, `>`, `>=` (operators)
Greater than. Has a few variants: `gt` (preferred) and `>` (alternative) will
check to see if a variable is strictly greater than a given variable or value,
while `>=` will be "greater than or equal to". Example:
```modulo
edit:demo=modulo
<Template>
{% if state.somevar gt 100 %}
This appears if variable somevar is greater than 100.
{% endif %}
</Template>
<State
somevar:=2600
></State>
```
## `in`, `not in` (operators)
Contained within. Unlike the built-in JavaScript operator "in" which is only
supported by Objects, this operator supports Strings, Arrays, and Objects as
the "container" types being checked. In all cases, it will test whether the
given value is within the given container. The `not in` operator does what you
might expect: The exact opposite of the `in` operator.
The following are some examples of how the `in` operator will be interpreted in
different contexts. Note that in these examples, some use hardcoded strings in
places (e.g. `"B.C.E"`), while others use variables in the same place (e.g.
`state.word`). As with every if-statement operator, you can either hardcoded
values and variables are interchangeable.
```modulo
edit:demo=modulo
<Template>
{% if "B.C.E." in state.era %} {# String context #}
<p>"B.C.E." is a substring of "{{ state.era }}"</p>
{% endif %}
{% if state.word in state.greetings %} {# Array context #}
<p>"{{ state.word }}" was found in: {{ state.greetings|join:", " }}</p>
{% endif %}
{% if "author" in state.article %} {# Object context #}
<p>Author was found in article: {{ state.article.author }}</p>
{% endif %}
</Template>
<State
era="3rd Century B.C.E. (Macedonia)"
word="hello"
greetings:='[
"hallo",
"hello",
"hola",
"óla"
]'
article:='{
"author": "Albert Einstein",
"publication": "Monthly Review"
}'
></State>
```