• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# @Observed and @ObjectLink
2
3
4This section introduces to you two new decorators: @Observed and @ObjectLink.
5
6
7- @Observed applies to a class, indicating that the data changes in the class are managed by the UI page, for example, @Observed class ClassA {}.
8
9- @ObjectLink applies to an object decorated by @Observed, for example, @ObjectLink a: ClassA.
10
11
12## Background
13
14When you need to set bidirectional synchronization in a child component for a variable (parent_a) of its parent component, you can use @State to decorate the variable (parent_a) in the parent component and use @Link to decorate the corresponding variable (child_a) in the child component. In this way, data can be synchronized between the parent component and the specific child component, and between the parent component and its other child components. As shown below, bidirectional synchronization is configured for variables of ClassA in the parent and child components. If attribute c of the variable in child component 1 has its value changed, the parent component will be notified to synchronize the change. If attribute c in the parent component has its value changed, all child components will be notified to synchronize the change.
15
16![en-us_image_0000001267647861](figures/en-us_image_0000001267647861.png)
17
18In the preceding example, full synchronization is performed for a data object. If you want to synchronize partial information of a data object in a parent component, and if the information is a class object, use @ObjectLink and @Observed instead, as shown below.
19
20![en-us_image_0000001267607881](figures/en-us_image_0000001267607881.png)
21
22
23## Configuration Requirement
24
25- @Observed applies to classes, and @ObjectLink applies to variables.
26
27- The variables decorated by @ObjectLink must be of the class type.
28  - The classes must be decorated by @Observed.
29  - Parameters of the primitive types are not supported. You can use @Prop to perform unidirectional synchronization.
30
31- @ObjectLink decorated variables are immutable.
32  - Attribute changes are allowed. If an object is referenced by multiple @ObjectLink decorated variables, all custom components that have these variables will be notified for re-rendering.
33
34- Default values cannot be set for @ObjectLink decorated variables.
35  - The parent component must be initialized with a TypeScript expression that involves variables decorated by @State, @Link, @StorageLink, @Provide, or @Consume.
36
37- @ObjectLink decorated variables are private variables and can be accessed only within the component.
38
39
40## Examples
41
42
43### Example 1
44
45
46```
47@Observed
48class ClassA {
49  public name : string;
50  public c: number;
51  constructor(c: number, name: string = 'OK') {
52    this.name = name;
53    this.c = c;
54  }
55}
56
57class ClassB {
58  public a: ClassA;
59  constructor(a: ClassA) {
60    this.a = a;
61  }
62}
63
64@Component
65struct ViewA {
66  label : string = "ep1";
67  @ObjectLink a : ClassA;
68  build() {
69    Column() {
70      Text(`ViewA [${this.label}]: a.c=${this.a.c}`)
71        .fontSize(20)
72      Button(`+1`)
73        .width(100)
74        .margin(2)
75        .onClick(() => {
76          this.a.c += 1;
77        })
78      Button(`reset`)
79        .width(100)
80        .margin(2)
81        .onClick(() => {
82          this.a = new ClassA(0); // ERROR, this.a is immutable
83        })
84    }
85  }
86}
87
88@Entry
89@Component
90struct ViewB {
91  @State b : ClassB = new ClassB(new ClassA(10));
92  build() {
93    Flex({direction: FlexDirection.Column, alignItems: ItemAlign.Center}) {
94      ViewA({label: "ViewA #1", a: this.b.a})
95      ViewA({label: "ViewA #2", a: this.b.a})
96
97      Button(`ViewB: this.b.a.c += 1` )
98        .width(320)
99        .margin(4)
100        .onClick(() => {
101          this.b.a.c += 1;
102        })
103      Button(`ViewB: this.b.a = new ClassA(0)`)
104        .width(240)
105        .margin(4)
106        .onClick(() => {
107          this.b.a = new ClassA(0);
108        })
109      Button(`ViewB: this.b = new ClassB(ClassA(0))`)
110        .width(240)
111        .margin(4)
112        .onClick(() => {
113          this.b = new ClassB(new ClassA(0));
114        })
115    }
116  }
117}
118```
119
120
121### Example 2
122
123
124```
125var nextID: number = 0;
126@Observed
127class ClassA {
128  public name : string;
129  public c: number;
130  public id : number;
131  constructor(c: number, name: string = 'OK') {
132    this.name = name;
133    this.c = c;
134    this.id = nextID++;
135  }
136}
137
138@Component
139struct ViewA {
140  label : string = "ViewA1";
141  @ObjectLink a: ClassA;
142  build() {
143    Row() {
144      Button(`ViewA [${this.label}] this.a.c= ${this.a.c} +1`)
145        .onClick(() => {
146          this.a.c += 1;
147        })
148    }
149  }
150}
151
152@Entry
153@Component
154struct ViewB {
155  @State arrA : ClassA[] = [ new ClassA(0), new ClassA(0) ];
156  build() {
157    Column() {
158      ForEach (this.arrA, (item) => {
159          ViewA({label: `#${item.id}`, a: item})
160        },
161        (item) => item.id.toString()
162      )
163      ViewA({label: `ViewA this.arrA[first]`, a: this.arrA[0]})
164      ViewA({label: `ViewA this.arrA[last]`, a: this.arrA[this.arrA.length-1]})
165
166      Button(`ViewB: reset array`)
167        .onClick(() => {
168            this.arrA = [ new ClassA(0), new ClassA(0) ];
169        })
170      Button(`ViewB: push`)
171        .onClick(() => {
172            this.arrA.push(new ClassA(0))
173        })
174      Button(`ViewB: shift`)
175        .onClick(() => {
176            this.arrA.shift()
177        })
178    }
179  }
180}
181```
182