---
title: TYML Reference
---

# TYML Reference

Tuya Markup Language (TYML) is the markup language dedicated for framework design, and works in tandem with the basic components and event system to build a page structure.

## Data binding

Dynamic data in TYML is bound with the `data` content in `Page`.

### Simple binding

The `Mustache` syntax is used to package variables with two pairs of braces (`{{variable}}`). The following examples show the cases in which `Mustache` can be used.

#### Content

```xml
<view> {{ message }} </view>
```

```js
Page({
  data: {
    message: 'Hello MINA!',
  },
});
```

#### Component attribute (enclosed with double quotation marks)

```xml
<view id="item-{{id}}"> </view>
```

```js
Page({
  data: {
    id: 0,
  },
});
```

#### Control attribute (enclosed with double quotation marks)

```xml
<view ty:if="{{condition}}"> </view>
```

```js
Page({
  data: {
    condition: true,
  },
});
```

#### Keyword (enclosed with double quotation marks)

`true`: the Boolean `true` to represent a true value.
`false`: the Boolean `false` to represent a false value.

```xml
<checkbox checked="{{false}}"> </checkbox>
```

**_Note: Do not directly use `checked="false"`. Otherwise, the computing result is a string, and after conversion to the Boolean type, represents a true value._**

### Operation

Simple operations can be enclosed with two pairs of braces `{{}}`. The following operations are supported:

#### Ternary operation

```xml
<view hidden="{{flag ? true : false}}"> Hidden </view>
```

#### Arithmetic operation

```xml
<view> {{a + b}} + {{c}} + d </view>
```

```js
Page({
  data: {
    a: 1,
    b: 2,
    c: 3,
  },
});
```

The content in `view` is `3 + 3 + d`.

#### Logic judgment

```xml
<view ty:if="{{length > 5}}"> </view>
```

#### String operation

```xml
<view>{{"hello" + name}}</view>
```

```js
Page({
  data: {
    name: 'MINA',
  },
});
```

#### Data path operation

```xml
<view>{{object.key}} {{array[0]}}</view>
```

```js
Page({
  data: {
    object: {
      key: 'Hello ',
    },
    array: ['MINA'],
  },
});
```

### Combination

You can combine data within `Mustache` (`{{}}`) to create a new object or array.

#### Array

```xml
<view ty:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
```

```js
Page({
  data: {
    zero: 0,
  },
});
```

The new array `[0, 1, 2, 3, 4]` is created.

#### Object

```xml
<template is="objectCombine" data="{{for: a, bar: b}}"></template>
```

```js
Page({
  data: {
    a: 1,
    b: 2,
  },
});
```

The new object `{for: 1, bar: 2}` is created.
You can use the spread operator (`…`) to spread an object.

```xml
<template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
```

```js
Page({
  data: {
    obj1: {
      a: 1,
      b: 2,
    },
    obj2: {
      c: 3,
      d: 4,
    },
  },
});
```

The new object `{a: 1, b: 2, c: 3, d: 4, e: 5}` is created.

The objects with the same `key` and `value` are handled in the following indirect expression:

```xml
<template is="objectCombine" data="{{foo, bar}}"></template>
```

```js
Page({
  data: {
    foo: 'my-foo',
    bar: 'my-bar',
  },
});
```

The new object `{foo: 'my-foo', bar:'my-bar'}` is created.

**Note**: You can combine the preceding methods randomly. However, for variables with the same name, the one last declared will overwrite the earlier ones. Example:

```xml
<template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>
```

```js
Page({
  data: {
    obj1: {
      a: 1,
      b: 2,
    },
    obj2: {
      b: 3,
      c: 4,
    },
    a: 5,
  },
});
```

The new object `{a: 5, b: 3, c: 6}` is created. **Note**: The white-space character (if any) between the braces and quotation mark will be parsed into a string. Example:

```xml
<view ty:for="{{[1,2,3]}} ">
  {{item}}
</view>
```

Equivalent to

```xml
<view ty:for="{{[1,2,3] + ' '}}">
  {{item}}
</view>
```

## Condition rendering

### ty:if

In the framework, `ty:if=""` is used to check whether to render a code block.

```xml
<view ty:if="{{condition}}"> True </view>
```

You can also combine `ty:elif` with `ty:else` to add an `else` branch.

```xml
<view ty:if="{{length > 5}}"> 1 </view>
<view ty:elif="{{length > 2}}"> 2 </view>
<view ty:else> 3 </view>
```

### block ty:if

`ty:if` is a control attribute, and can only be used in one component. For conditional rendering of multiple components at once, you can use a `<block/>` tag to contain these components, and add `ty:if` preceding these components.

```xml
<block ty:if="{{true}}">
  <view> view1 </view>
  <view> view2 </view>
</block>
```

Note: `<block/>` is not a component, but just a packaging element. It does not render anything on a page, but accepts control attributes only.

### ty:if vs hidden

The template in `ty:if` might contain data binding. So, when the `ty:if` condition value changes, the framework provides the process of local rendering to destroy or re-render the condition block in case of the change.

In addition, when the initial render condition is `false`, `ty:if` does not trigger any rendering action. Local rendering is started when the condition turns `true` for the first time.

In contrast, `hidden` is more simple. It controls the show or hide operation, and the component is always rendered.

Generally, `ty:if` has a higher overhead when frequently toggled. `hidden` has a higher initial rendering overhead. As a result, `hidden` is better for frequent toggles. If the running conditions do not toggle much, `ty:if` is preferred.

## List rendering

### ty:for

The `ty:for` attribute can be used in components to bind an array. This way, the data in the array can be used to repeatedly render components.

The current item in the array has a default subscript variable name `index`. The current item of the array has a default variable name `item`.

```xml
<view ty:for="{{array}}">
  {{index}}: {{item.message}}
</view>
```

```js
Page({
  data: {
    array: [
      {
        message: 'foo',
      },
      {
        message: 'bar',
      },
    ],
  },
});
```

Use `ty:for-item` to specify the variable name for the current element of the array.

Use `ty:for-index` to specify the current subscript variable name of the array.

```xml
<view ty:for="{{array}}" ty:for-index="idx" ty:for-item="itemName">
  {{idx}}: {{itemName.message}}
</view>
```

`ty:for` supports nesting. The following code block shows the Multiplication Table nesting.

```xml
<view ty:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" ty:for-item="i">
  <view ty:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" ty:for-item="j">
    <view ty:if="{{i <= j}}">
      {{i}} * {{j}} = {{i * j}}
    </view>
  </view>
</view>
```

### block ty:for

Similar to `block` `ty:if`, `ty:for` can be used in the `<block/>` tag to render a structural block with multiple nodes. Example:

```xml
<block ty:for="{{[1, 2, 3]}}">
  <view> {{index}}: </view>
  <view> {{item}} </view>
</block>
```

`ty:key`
If a list item dynamically changes its position or a new item is added to the list, and the items are expected to maintain their features and status in the list (for example, the entered content of `input` and the checked status of `switch`), `ty:key` must be used to specify the unique identifier of an item.

The value of `ty:key` is provided in the following two modes:

String: represents a `property` of an item in an `array` used in a `for` loop. The `property` value needs to be a unique string or number in the list and cannot change dynamically.
Reserved keyword `*this`: represents an `item` used in a `for` loop. The `item` is a unique string or number.
For example, when the change of the current data triggers re-rendering, the component with `key` will be rectified. The framework ensures they are reordered, but not recreated. In this way, the component can maintain its status to increase the list rendering efficiency.

If `ty:key` is not provided, a `warning` is reported. This can be ignored if the list is explicitly known as static or the order is not concerned.

### Example

```xml
<switch ty:for="{{objectArray}}" ty:key="unique" style="display: block;"> {{item.id}} </switch>
<button bind:tap="switch"> Switch </button>
<button bind:tap="addToFront"> Add to the front </button>

<switch ty:for="{{numberArray}}" ty:key="*this" style="display: block;"> {{item}} </switch>
<button bind:tap="addNumberToFront"> Add to the front </button>
```

```js
Page({
  data: {
    objectArray: [
      { id: 5, unique: 'unique_5' },
      { id: 4, unique: 'unique_4' },
      { id: 3, unique: 'unique_3' },
      { id: 2, unique: 'unique_2' },
      { id: 1, unique: 'unique_1' },
      { id: 0, unique: 'unique_0' },
    ],
    numberArray: [1, 2, 3, 4],
  },
  switch: function (e) {
    const length = this.data.objectArray.length;
    for (let i = 0; i < length; ++i) {
      const x = Math.floor(Math.random() * length);
      const y = Math.floor(Math.random() * length);
      const temp = this.data.objectArray[x];
      this.data.objectArray[x] = this.data.objectArray[y];
      this.data.objectArray[y] = temp;
    }
    this.setData({
      objectArray: this.data.objectArray,
    });
  },
  addToFront: function (e) {
    const length = this.data.objectArray.length;
    this.data.objectArray = [{ id: length, unique: 'unique_' + length }].concat(
      this.data.objectArray,
    );
    this.setData({
      objectArray: this.data.objectArray,
    });
  },
  addNumberToFront: function (e) {
    this.data.numberArray = [this.data.numberArray.length + 1].concat(
      this.data.numberArray,
    );
    this.setData({
      numberArray: this.data.numberArray,
    });
  },
});
```

### **Things to note**

#### 1. When the value of `ty:for` is a string, the string will be parsed into an array of strings.

```xml
<view ty:for="array">
  {{item}}
</view>
```

Equivalent to

```xml
<view ty:for="{{['a','r','r','a','y']}}">
  {{item}}
</view>
```

#### 2. The white-space character (if any) between the braces and quotation mark will be parsed into a string. Example:

```xml
<view ty:for="{{[1,2,3]}} ">
  {{item}}
</view>
```

Equivalent to

```xml
<view ty:for="{{[1,2,3] + ' '}}" >
  {{item}}
</view>
```

#### 3. When `ty:for` cannot be used together with `ty:else` `ty:elif`

Because `ty:for` will be parsed first, it will cause `ty:else` `ty:elif` to be a template syntax error.

```xml
<view ty:if="{{ condition1}}">conditon1</view>
<view ty:elif="{{ condition2 }}" ty:for="{{array}}">conditon2</view>
```

> The above template syntax error will cause compilation failure!

Correct usage:
```xml
<view ty:if="{{ condition1}}">conditon1</view>
<block ty:elif="{{ condition2 }}">
  <view ty:for="{{array}}">conditon2</view>
</block>
```

#### 4. When `ty:for` is used together with `ty:if`, `ty:for` will be parsed first

```xml
<view ty:for="{{ array }}" ty:if="{{ condition1 }}">conditon1</view>
```

Equivalent to

```xml
<block ty:for="{{array}}">
  <view ty:if="{{ condition1 }}">conditon1</view>
</block>
```

## Template

`TYML` provides `template`, in which the code snippet can be defined to be invoked elsewhere.

### Define template

Use the `name` attribute to declare a template name and then define the code snippet within `<template/>`.

```xml
<!--
  index: int
  msg: string
  time: string
-->
<template name="msgItem">
  <view>
    <text> {{index}}: {{msg}} </text>
    <text> Time: {{time}} </text>
  </view>
</template>
```

### Use template

Use the `is` attribute to declare the required template and then introduce the required `data`. Example:

```xml
<template is="msgItem" data="{{...item}}"/>
```

```js
Page({
  data: {
    item: {
      index: 0,
      msg: 'this is a template',
      time: '2022-02-22',
    },
  },
});
```

The `is` attribute allows you to use the Mustache syntax to dynamically decide the template to be rendered.

```xml
<template name="odd">
  <view> odd </view>
</template>
<template name="even">
  <view> even </view>
</template>

<block ty:for="{{[1, 2, 3, 4, 5]}}">
  <template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>
```

### Template action scope

A template has an action scope and can only use the data introduced by `data` and modules `<sjs />` defined in the module definition file.

## File reference

The TYML provides two file reference methods: `import` and `include`.

### import

The `import` method can be used to load a template in a file when the template is defined in another file and the latter file is referenced by the former file.

For example, a template named `item` is defined in the `item.tyml`.

```xml
<!-- item.tyml -->
<template name="item">
  <text>{{text}}</text>
</template>
```

When `item.tyml` is referenced in `index.tyml`, the item template can be used.

```xml
<import src="item.tyml"/>
<template is="item" data="{{text: 'forbar'}}"/>
```

### Import action scope

The `import` method has the concept of action scope. Only the template defined in the target file is imported, but the one imported into the target file is not imported.

**For example, C imports B and B imports A. In C, the template defined in B can be used. In B, the template defined in A can be used. However, in C, the template defined in A cannot be used.**

```xml
<!-- A.tyml -->
<template name="A">
  <text> A template </text>
</template>
<!-- B.tyml -->
<import src="a.tyml"/>
<template name="B">
  <text> B template </text>
</template>
<!-- C.tyml -->
<import src="b.tyml"/>
<template is="A"/>  <!-- Error! Can not use template when not import A. -->
<template is="B"/>
```

### include

The `include` method can be used to introduce the whole code except for `<template/>` and `<sjs/>`. This is equivalent to copying the code to the `include` position.

```xml
<!-- index.tyml -->
<include src="header.tyml"/>
<view> body </view>
<include src="footer.tyml"/>
<!-- header.tyml -->
<view> header </view>
<!-- footer.tyml -->
<view> footer </view>
```
