• 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## Constraints
19- **!!** does not support multi-layer parent-child component transfer.
20
21## Use Scenarios
22
23### Two-Way Binding Between Custom Components
241. 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.
25- The two-way binding syntactic sugar can be considered as:
26
27    ```
28    Star({ value: this.value, $value: (val: number) => { this.value = val }})
29    ```
302. 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.
313. 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.
32
33```ts
34@Entry
35@ComponentV2
36struct Index {
37  @Local value: number = 0;
38
39  build() {
40    Column() {
41      Text(`${this.value}`)
42      Button(`change value`).onClick(() => {
43        this.value++;
44      })
45      Star({ value: this.value!! })
46    }
47  }
48}
49
50
51@ComponentV2
52struct Star {
53  @Param value: number = 0;
54  @Event $value: (val: number) => void = (val: number) => {};
55
56  build() {
57    Column() {
58      Text(`${this.value}`)
59      Button(`change value `).onClick(() => {
60        this.$value(10);
61      })
62    }
63  }
64}
65```
66
67### Two-Way Binding Between Built-in Component Parameters
68
69The **!!** 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!!**.
70
71What 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.
72
73#### Rules of Use
74
75- 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.
76
77  | Attribute                                                        | Supported Parameter| Initial API Version|
78  | ------------------------------------------------------------ | --------------- | ----------- |
79  | [bindMenu](../reference/apis-arkui/arkui-ts/ts-universal-attributes-menu.md#bindmenu11) | isShow | 13          |
80  | [bindContextMenu](../reference/apis-arkui/arkui-ts/ts-universal-attributes-menu.md#bindcontextmenu12) | isShown | 13          |
81  | [bindPopup](../reference/apis-arkui/arkui-ts/ts-universal-attributes-popup.md#bindpopup) | show | 13   |
82
83- When the [\@Local](arkts-new-local.md) decorated variable bound to **!!** changes, the UI is rendered synchronously.
84
85
86#### Example
87
88Two-way binding of the **isShow** parameter of the **bindMenu** API:
89
90```ts
91@Entry
92@ComponentV2
93struct BindMenuInterface {
94  @Local isShow: boolean = false;
95
96  build() {
97    Column() {
98      Row() {
99        Text('click show Menu')
100          .bindMenu(this.isShow!!, // Two-way binding.
101            [
102              {
103                value: 'Menu1',
104                action: () => {
105                  console.info('handle Menu1 click');
106                }
107              },
108              {
109                value: 'Menu2',
110                action: () => {
111                  console.info('handle Menu2 click');
112                }
113              },
114            ])
115      }.height('50%')
116      Text("isShow: " + this.isShow).fontSize(18).fontColor(Color.Red)
117      Row() {
118        Button("Click")
119          .onClick(() => {
120            this.isShow = true;
121          })
122          .width(100)
123          .fontSize(20)
124          .margin(10)
125      }
126    }.width('100%')
127  }
128}
129```
130
131![bindMenu](figures/bindmenu_doublebind.gif)
132