Skip to content

Latest commit

 

History

History
210 lines (142 loc) · 6.57 KB

syntax.md

File metadata and controls

210 lines (142 loc) · 6.57 KB

Syntax

A quick cheatsheet of the tempura template syntax.

The tempura template syntax is very similar to the Handlebars or Mustache template syntax.
In fact, they're more similar than they are different!

General Notice Throughout this document, you'll notice that most examples include HTML tags or produce HTML output. This is done only because HTML is a common target. Tempura templates do not need to use or produce HTML content – it only cares about its own template syntax!

Overview

Templates are (hopefully!) an easier way to write and maintain view logic. Nearly all template engines, including tempura, parse your template files and generate a function (per template) that includes all your view logic and desired output.

Each of these functions is valid JavaScript and is waiting to accept an input object. Together, the input data and the render function produce the expected output.

Expressions

Values can be printed by wrapping content with the {{ and }} characters. These can appear anywhere within your template, and typically reference a variable name, although they could wrap any value.

When the template is evaluated, these expressions are replaced. For example:

{{#expect name}}
<p>Hello, {{ name }}!</p>

rendered with the input:

{ name: 'world' }

produces the result:

<p>Hello, world!</p>

Expression values can reference any defined variables. In this example, name was a simple string, but it could have been an object, an Array, or anything else!

For example, this template:

<p>Items left: {{ items.length }}</p>

with this input object:

{
  items: ["foo", "bar", "baz"]
}

produces this output:

<p>Items left: 3</p>

Escaped Values

By default, all expressions are HTML-escaped. For example, if the value contains the ", &, or < characters, they'd be encoded into the &quot;, &amp;, and &lt; sequences, respectively.

Note: The HTML-escape function can be customized via the escape option.

It's generally recommended to use HTML-escaping unless you're certain that the expression's value does not contain any HTML characters; eg, it's a number or you just constructed it via #var.

Raw Values

To disable HTML-escaping for a value, you must use the triple-curly syntax; for example {{{ value }}}.

When the triple-curly is used, the raw value is printed as is.

{{! input }}
escaped: {{ 'a & b " c < d' }}
raw: {{{ 'a & b " c < d' }}}
<!-- output -->
escaped: a &amp; b &quot; c &lt; d
raw: a & b " c < d

Comments

It's generally recommended to include comments within your templates, especially as their complexity grows!

Template comments will never appear in the rendered output. However, HTML comments are kept.

<!-- HTML comments are kept in output -->
{{! template comments are removed }}
{{!
  template comments
  can also be multi-line
  ...and are still removed
!}}
<p>hello world</p>

Helpers

The tempura syntax comes with few (but powerful) template helpers!

Unlike value expressions, template helpers – or "blocks" – always use double-curly tags. This is because they're not values, so there's no HTML-escape vs raw dilemma. The shorter, double-curly tag is used as a convenience.

Note: You may define your own helpers! See Custom Blocks for more detail.

#expect

A template needs to declare what variables it expects to receive. In several UI frameworks, this is generally referred to as defining your "props". At the parser level, this prepares the Compiler so that it won't throw any Uncaught ReferenceErrors during execution.

Note: You should hoist common variables via options.props to avoid repetitive #expect declarations.

You may declare multiple variables within the same #expect block. You may also have multiple #expect blocks in the same file:

{{#expect name}}
{{#expect foo, bar}}
{{#expect
    hello,
    title, todos }}

In this snippet, the rest of the template file may safely use the name, foo, bar, hello, title, and todos variables. If any of these variables had been referenced without being declared (either thru #expect or options.props), then a ReferenceError error would have been thrown at runtime.

This is because tempura prefers to be strict by default. If, however, you would prefer to relax this condition, you may enable the loose option during any tempura.compile or tempura.transform calls.

#var

You may define new variables within your template and reference them throughout the file. Normal JavaScript scoping rules apply.

These inline variables can evaluate any JavaScript and can reference other template variables.

Only one variable can be defined per #var block. You may have any number of #var blocks in your template:

{{#expect todos}}
{{#var numTotal = todos.length}}
{{#var numDone = todos.filter(x => x.done).length}}
{{#var numActive = numTotal = numDone}}

<p>You have {{{ numActive }}} item(s) remaining</p>
<p>You have {{{ numTotal }}} item(s) in total</p>

#if, #elif, #else

Your control flow helpers!

Just like JavaScript, use of #elif (short for else if) and #else are optional, but must always be associated with and follow an #if opener. Parenthesis around the #if and #elif conditions are optional:

All #if blocks must be terminated by an /if block.

{{#expect age, isActive}}

{{#if isActive}}
  <p>Good for you!</p>
{{/if}}

{{#if isActive}}
  <p>Good for you!</p>
{{#else}}
  <p>How about 1 hour a week?</p>
{{/if}}

{{#var senior = age >= 70}}

{{#if senior && isActive}}
  <p>Wow, that's amazing!</p>
{{#elif isActive}}
  <p>Good for you!</p>
{{#elif senior}}
  <p>How about water aerobics?</p>
{{#else}}
  <p>How about kick boxing?</p>
{{/if}}

#each

The #each block loops over an Array, passing through each value and index to the template expression(s) within the block.

All #each blocks must be terminated by an /each block.

{{#expect items}}

{{! only use the value }}
{{#each items as item}}
  <div class="task">
    <strong class="title">{{ item.title }}</strong>
    <span class="text">{{ item.text }}</span>
  </div>
{{/each}}

{{! use the value & index }}
{{#each items as item,index }}
  <div class="task" data-index="{{{ index }}}">
    <strong class="title">{{ item.title }}</strong>
    <span class="text">{{ item.text }}</span>
  </div>
{{/each}}