1# \@BuilderParam Decorator: @Builder Function Reference
2
3
4In certain circumstances, you may need to add a specific feature, such as a click-to-jump action, to a custom component. However, embedding an event method directly in a component will add the feature to all places where the component is imported. This is where the \@BuilderParam decorator comes into the picture. \@BuilderParam is used to decorate a custom component variable of type Reference to an [\@Builder](./arkts-builder.md) method (@BuilderParam is used to undertake the @Builder function). When initializing a custom component, you can add the specific feature to it by assigning a value to the variable. This decorator can be used to declare an element of any UI description, similar to a slot placeholder.
5
6
7> **NOTE**
8>
9> This decorator can be used in ArkTS widgets since API version 9.
10>
11> This decorator can be used in atomic services since API version 11.
12
13## Rules of Use
14
15
16### Initializing \@BuilderParam Decorated Methods
17
18An \@BuilderParam decorated method can be initialized only by an \@Builder function reference. If this decorator is used together with [\@Require](arkts-require.md) in API version 11, the parent component must construct input parameters.
19
20- Local initialization with the owning component's custom \@Builder function reference or a global \@Builder function reference
21
22  ```ts
23  @Builder function overBuilder() {}
24
25  @Component
26  struct Child {
27    @Builder doNothingBuilder() {};
28
29    // Use the custom builder function of the custom component for @BuilderParam initialization.
30    @BuilderParam customBuilderParam: () => void = this.doNothingBuilder;
31    // Use the global custom builder function for @BuilderParam initialization.
32    @BuilderParam customOverBuilderParam: () => void = overBuilder;
33    build(){}
34  }
35  ```
36
37- Initialization from the parent component
38
39  ```ts
40  @Component
41  struct Child {
42    @Builder customBuilder() {};
43    // Use the @Builder decorated method in the parent component for @BuilderParam initialization.
44    @BuilderParam customBuilderParam: () => void = this.customBuilder;
45
46    build() {
47      Column() {
48        this.customBuilderParam()
49      }
50    }
51  }
52
53  @Entry
54  @Component
55  struct Parent {
56    @Builder componentBuilder() {
57      Text(`Parent builder `)
58    }
59
60    build() {
61      Column() {
62        Child({ customBuilderParam: this.componentBuilder })
63      }
64    }
65  }
66  ```
67  **Figure 1** Example effect
68
69  ![builderparam-demo1](figures/builderparam-demo1.png)
70
71
72- **this** in the function body must point to the correct object.
73
74Example:
75
76  ```ts
77  @Component
78  struct Child {
79    label: string = `Child`;
80    @Builder customBuilder() {};
81    @Builder customChangeThisBuilder() {};
82    @BuilderParam customBuilderParam: () => void = this.customBuilder;
83    @BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder;
84
85    build() {
86      Column() {
87        this.customBuilderParam()
88        this.customChangeThisBuilderParam()
89      }
90    }
91  }
92
93  @Entry
94  @Component
95  struct Parent {
96    label: string = `Parent`;
97
98    @Builder componentBuilder() {
99      Text(`${this.label}`)
100    }
101
102    build() {
103      Column() {
104        // When this.componentBuilder() is called, this points to the Parent component decorated by the @Entry. That is, the value of the label variable is Parent.
105        this.componentBuilder()
106        Child({
107          // Pass this.componentBuilder to @BuilderParam customBuilderParam of the Child component. this points to the Child, that is, the value of the label variable is Child.
108          customBuilderParam: this.componentBuilder,
109          // pass ():void=>{this.componentBuilder () } to @BuilderParam customChangeThisBuilderPara of Child component.
110          // this of the arrow function points to the host object, so the value of the label variable is Parent.
111          customChangeThisBuilderParam: (): void => { this.componentBuilder() }
112        })
113      }
114    }
115  }
116  ```
117 **Figure 2** Example effect
118
119 ![builderparam-demo2](figures/builderparam-demo2.png)
120
121
122## Use Scenarios
123
124
125### Component Initialization Through Parameters
126
127An \@BuilderParam decorated method can be a method with or without parameters. Whether it contains parameters should match that of the assigned \@Builder method. The type of the \@BuilderParam decorated method must also match that of the assigned \@Builder method.
128
129```ts
130class Tmp{
131  label: string = '';
132}
133
134@Builder function overBuilder($$: Tmp) {
135  Text($$.label)
136    .width(400)
137    .height(50)
138    .backgroundColor(Color.Green)
139}
140
141@Component
142struct Child {
143  label: string = 'Child';
144  @Builder customBuilder() {};
145  // Without parameters. The pointed componentBuilder does not carry parameters either.
146  @BuilderParam customBuilderParam: () => void = this.customBuilder;
147  // With parameters. The pointed overBuilder also carries parameters.
148  @BuilderParam customOverBuilderParam: ($$: Tmp) => void = overBuilder;
149
150  build() {
151    Column() {
152      this.customBuilderParam()
153      this.customOverBuilderParam({label: 'global Builder label' } )
154    }
155  }
156}
157
158@Entry
159@Component
160struct Parent {
161  label: string = 'Parent';
162
163  @Builder componentBuilder() {
164    Text(`${this.label}`)
165  }
166
167  build() {
168    Column() {
169      this.componentBuilder()
170      Child({ customBuilderParam: this.componentBuilder, customOverBuilderParam: overBuilder })
171    }
172  }
173}
174```
175**Figure 3** Example effect
176
177![builderparam-demo3](figures/builderparam-demo3.png)
178
179
180### Component Initialization Through Trailing Closure
181
182In a custom component, the \@BuilderParam decorated attribute can be initialized using a trailing closure. During initialization, the component name is followed by a pair of braces ({}) to form a trailing closure.
183
184> **NOTE**
185>
186>  - In this scenario, the custom component can have only one \@BuilderParam decorated attribute.
187> 
188>  - In this scenario, custom components do not support universal attributes.
189
190You can pass the content in the trailing closure to \@BuilderParam as an \@Builder decorated method. Example:
191
192
193```ts
194@Component
195struct CustomContainer {
196  @Prop header: string = '';
197  @Builder closerBuilder(){};
198  // Use the trailing closure {} (@Builder decorated method) of the parent component for @BuilderParam initialization.
199  @BuilderParam closer: () => void = this.closerBuilder;
200
201  build() {
202    Column() {
203      Text(this.header)
204        .fontSize(30)
205      this.closer()
206    }
207  }
208}
209
210@Builder function specificParam(label1: string, label2: string) {
211  Column() {
212    Text(label1)
213      .fontSize(30)
214    Text(label2)
215      .fontSize(30)
216  }
217}
218
219@Entry
220@Component
221struct CustomContainerUser {
222  @State text: string = 'header';
223
224  build() {
225    Column() {
226      // Create the CustomContainer component. During initialization, append a pair of braces ({}) to the component name to form a trailing closure.
227      // Used as the parameter passed to CustomContainer @BuilderParam closer: () => void.
228      CustomContainer({ header: this.text }) {
229        Column() {
230          specificParam('testA', 'testB')
231        }.backgroundColor(Color.Yellow)
232        .onClick(() => {
233          this.text = 'changeHeader';
234        })
235      }
236    }
237  }
238}
239```
240**Figure 4** Example effect
241
242![builderparam-demo4](figures/builderparam-demo4.png)
243
244### \@BuilderParam Initialization Through Global and Local \@Builder
245
246In a custom component, the \@BuilderParam decorated variable is used to receive the content passed by the parent component through \@Builder for initialization. The \@Builder of the parent component can use the arrow function to change the object that this points to, therefore, when a \@BuilderParam decorated variable is used, different content is displayed.
247
248```ts
249@Component
250struct ChildPage {
251  label: string = `Child Page`;
252  @Builder customBuilder() {};
253  @BuilderParam customBuilderParam: () => void = this.customBuilder;
254  @BuilderParam customChangeThisBuilderParam: () => void = this.customBuilder;
255
256  build() {
257    Column() {
258      this.customBuilderParam()
259      this.customChangeThisBuilderParam()
260    }
261  }
262}
263
264const builder_value: string = 'Hello World';
265@Builder function overBuilder() {
266  Row() {
267    Text(`Global Builder: ${builder_value}`)
268      .fontSize(20)
269      .fontWeight(FontWeight.Bold)
270  }
271}
272
273@Entry
274@Component
275struct ParentPage {
276  label: string = `Parent Page`;
277
278  @Builder componentBuilder() {
279    Row(){
280      Text(`Local Builder:${this.label}`)
281        .fontSize(20)
282        .fontWeight(FontWeight.Bold)
283    }
284  }
285
286  build() {
287    Column() {
288      // When this.componentBuilder() is called, this points to the **ParentPage** component decorated by the @Entry. Therefore, the value of the label variable is Parent Page.
289      this.componentBuilder()
290      ChildPage({
291        // Pass this.componentBuilder to @BuilderParam customBuilderParam of ChildPage component. this points to ChildPage, that is, the value of the label variable is Child Page.
292        customBuilderParam: this.componentBuilder,
293        // Pass ():void=>{this.componentBuilder () } to @BuilderParam customChangeThisBuilderPara of ChildPage component.
294        // this of the arrow function points to the host object, so the value of the label variable is Parent Page.
295        customChangeThisBuilderParam: (): void => { this.componentBuilder() }
296      })
297      Line()
298        .width('100%')
299        .height(10)
300        .backgroundColor('#000000').margin(10)
301      // When the global overBuilder() is called, this points to the entire current page. Therefore, the displayed content is Hello World.
302      overBuilder()
303      ChildPage({
304        // Pass the global overBuilder to @BuilderParam customBuilderParam of the ChildPage component. this points to the entire current page, that is, the displayed content is Hello World.
305        customBuilderParam: overBuilder,
306        // Pass the global overBuilder to @BuilderParam customChangeThisBuilderParam of the ChildPage component. this points to the entire current page, that is, the displayed content is Hello World.
307        customChangeThisBuilderParam: overBuilder
308      })
309    }
310  }
311}
312```
313**Figure 5** Example effect
314
315![builderparam-demo5](figures/builderparam-demo5.png)
316
317## FAQs
318
319### UI Re-rendering Fails When Content Is Changed
320
321When the custom component **ChildPage** is called, \@Builder is passed as a parameter through **this.componentBuilder**. Currently, this points to the custom component. Therefore, if the **label** value is changed inside the parent component, the custom component **ChildPage** cannot detect the change.
322
323[Incorrect Example]
324
325```ts
326@Component
327struct ChildPage {
328  @State label: string = `Child Page`;
329  @Builder customBuilder() {};
330  @BuilderParam customChangeThisBuilderParam: () => void = this.customBuilder;
331
332  build() {
333    Column() {
334      this.customChangeThisBuilderParam()
335    }
336  }
337}
338
339@Entry
340@Component
341struct ParentPage {
342  @State label: string = `Parent Page`;
343
344  @Builder componentBuilder() {
345    Row(){
346      Text(`Builder :${this.label}`)
347        .fontSize(20)
348        .fontWeight(FontWeight.Bold)
349    }
350  }
351
352  build() {
353    Column() {
354      ChildPage({
355        customChangeThisBuilderParam: this.componentBuilder // Incorrect parameter passing.
356      })
357      Button('Click to change label')
358        .onClick(() => {
359          this.label = 'Hello World';
360        })
361    }
362  }
363}
364```
365
366Use the arrow function to pass the \@Builder to the custom component **ChildPage** and this points to the parent component **ParentPage**. Therefore, if the value of label is changed in the parent component, the **ChildPage** detects the change and renders the UI again.
367
368[Correct Example]
369
370```ts
371@Component
372struct ChildPage {
373  @State label: string = `Child Page`;
374  @Builder customBuilder() {};
375  @BuilderParam customChangeThisBuilderParam: () => void = this.customBuilder;
376
377  build() {
378    Column() {
379      this.customChangeThisBuilderParam()
380    }
381  }
382}
383
384@Entry
385@Component
386struct ParentPage {
387  @State label: string = `Parent Page`;
388
389  @Builder componentBuilder() {
390    Row(){
391      Text(`Builder :${this.label}`)
392        .fontSize(20)
393        .fontWeight(FontWeight.Bold)
394    }
395  }
396
397  build() {
398    Column() {
399      ChildPage({
400        customChangeThisBuilderParam: () => { this.componentBuilder() }
401      })
402      Button('Click to change label')
403        .onClick(() => {
404          this.label = 'Hello World';
405        })
406    }
407  }
408}
409```
410