• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# !! Syntax: Enabling Two-Way Binding
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @Cuecuexiaoyu-->
5<!--Designer: @lixingchi1-->
6<!--Tester: @TerryTsao-->
7<!--Adviser: @zhang_yixin13-->
8
9In state management V1, two-way binding for built-in components is implemented using [$$](./arkts-two-way-sync.md).
10In state management V2, the **!!** syntactic sugar provides a unified way to achieve two-way binding for components.
11
12>**NOTE**
13>
14>The **!!** syntax is supported since API version 12.
15>
16
17## Overview
18
19The **!!** syntactic sugar enables two-way binding for components by initializing the [\@Param](arkts-new-param.md) and [\@Event](arkts-new-event.md) decorated variables of child components. For this to work, the \@Event decorated method name must be declared as **$** + the name of the \@Param decorated attribute. For details, see [Use Scenarios](#use-scenarios).
20
21- When **!!** is used, changes in the parent component are synchronized to the child component, and vice versa, achieving two-way synchronization.
22- If **!!** is not used, changes flow only from the parent to the child, which means one-way synchronization.
23
24## Use Scenarios
25
26### Two-Way Binding Between Custom Components
271. In the **Index** component, construct a child **Star** component and use **!!** to enable two-way binding for the **value** attribute. This automatically initializes the child component's **@Param value** and **@Event $value**.
28
29   **!!** syntactic sugar for two-way binding:
30
31   ```
32   Star({ value: this.value, $value: (val: number) => { this.value = val; }})
33   ```
342. Clicking the button in **Index** (parent) increments the value of **value**, and the **Text** components in both **Index** and **Star** (child) are updated.
353. Clicking the button in **Star** (child) calls **this.$value(10)**, and the **Text** components in both **Index** and **Star** are updated.
36
37   ```ts
38   @Entry
39   @ComponentV2
40   struct Index {
41     @Local value: number = 0;
42
43     build() {
44       Column() {
45         Text(`${this.value}`)
46         Button(`change value`).onClick(() => {
47           this.value++;
48         })
49         Star({ value: this.value!! })
50       }
51     }
52   }
53
54
55   @ComponentV2
56   struct Star {
57     @Param value: number = 0;
58     @Event $value: (val: number) => void = (val: number) => {};
59
60     build() {
61       Column() {
62         Text(`${this.value}`)
63         Button(`change value`).onClick(() => {
64           this.$value(10);
65         })
66       }
67     }
68   }
69   ```
70
71**Constraints**
72- **!!** does not support two-way binding across multiple layers of parent-child components.
73- **!!** cannot be used together with \@Event. Since API version 18, using **!!** to pass parameters to a child component's @Event method causes a compilation error.
74- Using three or more exclamation marks (such as **!!!** and **!!!!**) does not enable two-way binding.
75
76
77### Two-Way Binding Between Built-in Component Parameters
78
79The **!!** operator passes a TypeScript variable by reference to a built-in component, ensuring the variable's value and the component's internal state stay in sync. To use this operator, append it to the variable name, for example, **isShow!!**.
80
81The specific meaning of the "internal state" is determined by the component implementation. For example, the **isShow** parameter in [bindMenu](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-menu.md#bindmenu11) controls menu visibility.
82
83```ts
84@Entry
85@ComponentV2
86struct BindMenuInterface {
87  @Local isShow: boolean = false;
88
89  build() {
90    Column() {
91      Row() {
92        Text('click show Menu')
93          .bindMenu(this.isShow!!, // Two-way binding.
94            [
95              {
96                value: 'Menu1',
97                action: () => {
98                  console.info('handle Menu1 click');
99                }
100              },
101              {
102                value: 'Menu2',
103                action: () => {
104                  console.info('handle Menu2 click');
105                }
106              },
107            ])
108      }.height('50%')
109      Text('isShow: ' + this.isShow).fontSize(18).fontColor(Color.Red)
110      Row() {
111        Button('Click')
112          .onClick(() => {
113            this.isShow = true;
114          })
115          .width(100)
116          .fontSize(20)
117          .margin(10)
118      }
119    }.width('100%')
120  }
121}
122```
123
124![bindMenu](figures/bindmenu_doublebind.gif)
125
126**Usage Rules**
127
128- Currently, two-way binding with **!!** supports variables of basic types. When such variables are decorated with state management V1 decorators such as [\@State](arkts-state.md), or state management V2 decorators such as [\@Local](arkts-new-local.md), changes in variable values will trigger UI updates.
129
130  | Attribute                                                        | Supported Parameter| Initial API Version|
131  | ------------------------------------------------------------ | --------------- | ----------- |
132  | [bindMenu](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-menu.md#bindmenu11) | isShow | 18        |
133  | [bindContextMenu](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-menu.md#bindcontextmenu12) | isShown | 18          |
134  | [bindPopup](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-popup.md#bindpopup) | show | 18   |
135  | [TextInput](../../reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md#textinputoptions) | text | 18   |
136  | [TextArea](../../reference/apis-arkui/arkui-ts/ts-basic-components-textarea.md#textareaoptions) | text | 18   |
137  | [Search](../../reference/apis-arkui/arkui-ts/ts-basic-components-search.md#searchoptions18) | value | 18   |
138  | [BindSheet](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-sheet-transition.md#bindsheet) | isShow | 18   |
139  | [BindContentCover](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-modal-transition.md#bindcontentcover) | isShow | 18   |
140  | [SideBarContainer](../../reference/apis-arkui/arkui-ts/ts-container-sidebarcontainer.md#sidebarwidth) | sideBarWidth | 18   |
141  | [Navigation](../../reference/apis-arkui/arkui-ts/ts-basic-components-navigation.md#navbarwidth9) | navBarWidth | 18   |
142  | [Toggle](../../reference/apis-arkui/arkui-ts/ts-basic-components-toggle.md#toggleoptions18) | isOn | 18   |
143  | [Checkbox](../../reference/apis-arkui/arkui-ts/ts-basic-components-checkbox.md#select) | select | 18   |
144  | [CheckboxGroup](../../reference/apis-arkui/arkui-ts/ts-basic-components-checkboxgroup.md#selectall) | selectAll | 18   |
145  | [Radio](../../reference/apis-arkui/arkui-ts/ts-basic-components-radio.md#checked) | checked | 18   |
146  | [Rating](../../reference/apis-arkui/arkui-ts/ts-basic-components-rating.md#ratingoptions18) | rating | 18   |
147  | [Slider](../../reference/apis-arkui/arkui-ts/ts-basic-components-slider.md#slideroptions) | value | 18   |
148  | [Select](../../reference/apis-arkui/arkui-ts/ts-basic-components-select.md#selected) | selected | 18   |
149  | [Select](../../reference/apis-arkui/arkui-ts/ts-basic-components-select.md#value) | value | 18   |
150  | [MenuItem](../../reference/apis-arkui/arkui-ts/ts-basic-components-menuitem.md#selected) | selected | 18   |
151