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 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 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