create-modulo
Version:
Starter projects for Modulo.html - Ready for all uses - Markdown-SSG / SSR / API-backed SPA
242 lines (190 loc) • 6.48 kB
HTML
<script src=../static/Modulo.html></script><script type=md>---
title: Template - Component Parts
---
# Template
The _Template_ Component Part allow components to render their HTML content using a
tiny domain-specific language, called the _Modulo Templating Language_.
Without a _Template_ Component Part (or equivalent custom code), the default behavior of
the _Component_ Component Part is to make no attempt to alter their contents. However,
most components require complicated HTML structures within them. This is where
Templates come into play: They generate the `innerHTML` of a component.
Templates are not DOM-based, but instead render synchronously to a String
during the `render` [lifecycle phase](/docs/lifecycle.html), and
store the results in `renderObj.component.innerHTML`. The _Component_ Component Part
will read this HTML code during the `reconcile` phase and then "reconcile",
modify it's contents to resemble the target innerHTML. (More on this is in [the
Component Component Part documentation above](/docs/core/component.html).)
Every time a Component renders, the Template will render using the _renderObj_
as a "template context", or, in other words, using the various Component Part's
contributions to the _renderObj_ as Template variables that can be inserted
into the HTML.
## Templating reference
[See the Templating documentation for further information on the functionality
of the Templating Component Part.](/docs/templating/index.html)
# Example Usage
## Example #1: Simple template
```modulo
edit:demo=modulo
<Template>
{# Code in this format is a comment #}
{# Use state variables such as "state.count" as such #}
<p>The count is: <em>{{ state.count }}</em></p>
{# Using a |filter we can modfiy data on the fly #}
<p>The next count is: <em>{{ state.count|add:1 }}</em></p>
{# Using a "template tag" we check value #}
{% if state.count gt 9 %}
<p>The count has reached 10!</p>
{% endif %}
</Template>
<State
count:=42
></State>
```
## Example #2: Complex template
```modulo
edit:demo=modulo
<Template>
<p>There are <em>{{ state.count }} articles</em></p>
{# Show the articles #}
{% for article in state.articles %}
<h4 style="color: blue">{{ article.headline|upper }}</h4>
{% if article.tease %}
<p>{{ article.tease|truncate:30 }}</p>
{% endif %}
{% endfor %}
</Template>
<!-- The data below was used to render the template above -->
<State
count:=42
articles:='[
{"headline": "Modulo released!",
"tease": "The most exciting news of the century."},
{"headline": "Can JS be fun again?"},
{"headline": "MTL considered harmful",
"tease": "Why constructing JS is risky business."}
]'
></State>
```
## Example #3: Multiple templates with include
Note that in a full example, you might consider loading all or some Templates
using a `-src=` attribute, so you can edit the HTML files separately.
Also note that in mutli-template components, one should have no name (or have `active:=true`).
```modulo
edit:demo=modulo
<Template -name="header">
<p><strong>{{ state.title }}</strong></p>
</Template>
<Template -name="body">
{% for para in state.paras %}
<p>{{ para }}</p>
{% endfor %}
</Template>
<Template>
<div class="container">
<section>
<article>
<div>
{% include header %}
</div>
<main>
{% include body %}
</main>
<article>
</section>
</div>
</Template>
<State
title="Multi-Template World"
paras:='[ "A b c", "1 2 3", "Do re mi", "Togeprrrrri" ]'
></State>
<Style>
.container {
border: 1px solid gray;
margin: 5%;
padding: 5%;
background: white;
box-shadow: 5px 5px 5px #00000033;
}
section, article, main, div, p {
margin: 1%;
padding: 1%;
box-shadow: 0 0 2px #ff000033;
}
</Style>
```
## Example #4: Multiple templates, chosen with slider
```modulo
edit:demo=modulo
<Template -name="template_a">
<h1>First template</h1>
<p>AAA</p>
</Template>
<Template -name="template_b">
<h1>The second include</h1>
<p>BBB</p>
</Template>
<Template -name="template_c">
<h1>Final Include</h1>
<p>CCC</p>
</Template>
<Template>
<input state.bind name="val"
type="range" min="1" max="3" step="1" />
{% if state.val is 1 %}
{% include template_a %}
{% elif state.val is 2 %}
{% include template_b %}
{% else %}
{% include template_c %}
{% endif %}
</Template>
<State
val:=1
></State>
```
## Example #4: Style templates
By defining a `<style Template>`, can use the Modulo templating language to
apply "templating" to CSS:
```modulo
edit:demo=modulo
<Template>
<section style="display: grid; grid-template-columns: 1fr 2fr">
<label>Color</label>
<input state.bind name="bg" type="color" />
{% for key, value in state.shape %}
<label>{{ key|capfirst }}</label>
<input state.bind name="shape.{{ key }}" type="range" min="1" max="50" />
{% endfor %}
</section>
<div style="{% include div_style %}">LOREM IPSUM</div>
<pre>div { {% include div_style %} }</pre>
</Template>
<style Template -filter-content="trim:'x {,}'" -name="div_style">
x {
color: white;
background-color: {{ state.bg }};
{% for key, value in state.shape %} {{ key }}: {{ value }}px;
{% endfor %}
}
</style>
<State
bg="#308330"
shape:={}
shape.width:=50
shape.height:=30
shape.padding:=5
shape.margin:=2
></State>
```
Note the following two unusual aspects of this example. Both of these are
optional, but only intended to make the Component Part easier to read, and for editors
to automatically apply syntax highlighting as expected.
- Observe how in the example below we use `-filter-content=` in order to "trim"
away our placeholder CSS (`x { ... }`). This makes editing this _Template_
Component Part easier to read, since it will follow standard `<style>` syntax rule,
thus the `x` just functioning as a purely cosmetic placeholder element.
- Observe how we use this dual tag format (`<style Template>`). To Modulo, this
is the same as doing `<Template>`. However, using a `style` tag makes it
easier to read, and syntax highlighting will work automatically. Thus, in
this case we can use the Modulo feature that lets the first attribute instead
determine the Component Part name instead of the actual tag name.