• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# !! Syntax: Two-Way Binding
2In state management V1, [$$](./arkts-two-way-sync.md) is used for two-way binding of built-in components.
3In state management V2, the **!!** syntactic sugar is used to implement two-way binding of components in a unified manner.
4
5
6>**NOTE**
7>
8>The **!!** syntax is supported since API version 12.
9>
10
11## Overview
12
13**!!** is a syntactic sugar used to implement two-way binding of components in initialization of \@Param and \@Event of the child components. The \@Event method name must be declared as "$" + \@Param attribute name. For details, see [Use Scenarios](#use-scenarios).
14
15- If the parent component uses **!!**, the change of the parent component will be synchronized to the child component, and vice versa.
16- If the parent component does not use **!!**, the change of the parent component is unidirectional.
17
18
19## Use Scenarios
20
21### Two-Way Binding Between Custom Components
221. Construct the **Star** child component in the **Index** component, bind the value in the parent and child components bidirectionally, and initialize **@Param value** and **@Event $value** of the child component.
23- The two-way binding syntactic sugar can be considered as:
24
25    ```
26    Star({ value: this.value, $value: (val: number) => { this.value = val }})
27    ```
282. Click the button in the **Index** component to change the value, and **Text** in both the parent component **Index** and child component **Star** will be updated.
293. Click the button in the child component **Star** to invoke **this.$value(10)**, and **Text** in both the parent component **Index** and child component **Star** will be updated.
30
31```ts
32@Entry
33@ComponentV2
34struct Index {
35  @Local value: number = 0;
36
37  build() {
38    Column() {
39      Text(`${this.value}`)
40      Button(`change value`).onClick(() => {
41        this.value++;
42      })
43      Star({ value: this.value!! })
44    }
45  }
46}
47
48
49@ComponentV2
50struct Star {
51  @Param value: number = 0;
52  @Event $value: (val: number) => void = (val: number) => {};
53
54  build() {
55    Column() {
56      Text(`${this.value}`)
57      Button(`change value `).onClick(() => {
58        this.$value(10);
59      })
60    }
61  }
62}
63```
64
65
66## Constraints
67- **!!** does not support multi-layer parent-child component transfer.
68- **!!** cannot be used together with @Event. Since API version 18, when **!!** is used to pass parameters to the @Event method of a child component, a compilation error is reported.
69- When three or more exclamation marks (!!!, !!!!, or !!!!!) are used, two-way binding is not supported.
70
71
72### Two-Way Binding Between Built-in Component Parameters
73
74The **!!** operator provides a TypeScript variable by-reference to a built-in component so that the variable value and the internal state of that component are kept in sync. Add this operator after the variable name, for example, **isShow!!**.
75
76What the internal state is depends on the component. For example, the **isShow** parameter of the [bindMenu](../reference/apis-arkui/arkui-ts/ts-universal-attributes-menu.md) component.
77
78#### Rules of Use
79
80- Currently, **!!** supports two-way binding of the following parameters of the basic types, that is, the parameters can synchronize the current menu or popup state. In addition, **!!** supports two-way binding of variables of the basic types as well. When a variable is decorated by [\@Local](arkts-new-local.md) of V2 or [\@State](arkts-state.md) of V1, the change of the variable value triggers the UI re-render.
81
82  | Attribute                                                        | Supported Parameter| Initial API Version|
83  | ------------------------------------------------------------ | --------------- | ----------- |
84  | [bindMenu](../reference/apis-arkui/arkui-ts/ts-universal-attributes-menu.md#bindmenu11) | isShow | 13          |
85  | [bindContextMenu](../reference/apis-arkui/arkui-ts/ts-universal-attributes-menu.md#bindcontextmenu12) | isShown | 13          |
86  | [bindPopup](../reference/apis-arkui/arkui-ts/ts-universal-attributes-popup.md#bindpopup) | show | 13   |
87  | [TextInput](../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md#textinputoptions)| text | 18   |
88  | [TextArea](../reference/apis-arkui/arkui-ts/ts-basic-components-textarea.md#textareaoptions)| text | 18   |
89  | [Search](../reference/apis-arkui/arkui-ts/ts-basic-components-search.md#searchoptions18)| value | 18   |
90  | [BindSheet](../reference/apis-arkui/arkui-ts/ts-universal-attributes-sheet-transition.md) | isShow | 18   |
91  | [BindContentCover](../reference/apis-arkui/arkui-ts/ts-universal-attributes-modal-transition.md) | isShow | 18   |
92  | [Toggle](../reference/apis-arkui/arkui-ts/ts-basic-components-toggle.md#toggleoptions18)| isOn | 18   |
93  | [Checkbox](../reference/apis-arkui/arkui-ts/ts-basic-components-checkbox.md#select) | select | 18   |
94  | [CheckboxGroup](../reference/apis-arkui/arkui-ts/ts-basic-components-checkboxgroup.md#selectall) | selectAll | 18   |
95  | [Radio](../reference/apis-arkui/arkui-ts/ts-basic-components-radio.md#checked) | checked | 18   |
96  | [Rating](../reference/apis-arkui/arkui-ts/ts-basic-components-rating.md#ratingoptions18)| rating | 18   |
97  | [Slider](../reference/apis-arkui/arkui-ts/ts-basic-components-slider.md#slideroptions)| value | 18   |
98  | [Select](../reference/apis-arkui/arkui-ts/ts-basic-components-select.md#selected) | selected | 18   |
99  | [Select](../reference/apis-arkui/arkui-ts/ts-basic-components-select.md#value) | value | 18   |
100  | [MenuItem](../reference/apis-arkui/arkui-ts/ts-basic-components-menuitem.md#selected) | selected | 18   |
101- When the [\@Local](arkts-new-local.md) decorated variable bound to **!!** changes, the UI is rendered synchronously.
102
103
104#### Example
105
106Two-way binding of the **isShow** parameter of the **bindMenu** API:
107
108```ts
109@Entry
110@ComponentV2
111struct BindMenuInterface {
112  @Local isShow: boolean = false;
113
114  build() {
115    Column() {
116      Row() {
117        Text('click show Menu')
118          .bindMenu(this.isShow!!, // Two-way binding.
119            [
120              {
121                value: 'Menu1',
122                action: () => {
123                  console.info('handle Menu1 click');
124                }
125              },
126              {
127                value: 'Menu2',
128                action: () => {
129                  console.info('handle Menu2 click');
130                }
131              },
132            ])
133      }.height('50%')
134      Text("isShow: " + this.isShow).fontSize(18).fontColor(Color.Red)
135      Row() {
136        Button("Click")
137          .onClick(() => {
138            this.isShow = true;
139          })
140          .width(100)
141          .fontSize(20)
142          .margin(10)
143      }
144    }.width('100%')
145  }
146}
147```
148
149![bindMenu](figures/bindmenu_doublebind.gif)
150