1e41f4b71Sopenharmony_ci# Updating Widget Content Through the router or call Event
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ciOn the widget page, the [postCardAction](../reference/apis-arkui/js-apis-postCardAction.md#postcardaction) API can be used to trigger a router or call event to start a UIAbility, which then updates the widget content. The following is an example of this widget update mode.
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ci> **NOTE**
7e41f4b71Sopenharmony_ci>
8e41f4b71Sopenharmony_ci> This topic describes development for dynamic widgets. For static widgets, see [FormLink](../reference/apis-arkui/arkui-ts/ts-container-formlink.md).
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ci## Updating Widget Content Through the router Event
11e41f4b71Sopenharmony_ci
12e41f4b71Sopenharmony_ci- On the widget page, register the **onClick** event callback of the button and call the **postCardAction** API in the callback to trigger the router event to start the UIAbility.
13e41f4b71Sopenharmony_ci  
14e41f4b71Sopenharmony_ci  ```ts
15e41f4b71Sopenharmony_ci  let storageUpdateRouter = new LocalStorage();
16e41f4b71Sopenharmony_ci  
17e41f4b71Sopenharmony_ci  @Entry(storageUpdateRouter)
18e41f4b71Sopenharmony_ci  @Component
19e41f4b71Sopenharmony_ci  struct WidgetUpdateRouterCard {
20e41f4b71Sopenharmony_ci    @LocalStorageProp('routerDetail') routerDetail: ResourceStr = $r('app.string.init');
21e41f4b71Sopenharmony_ci  
22e41f4b71Sopenharmony_ci    build() {
23e41f4b71Sopenharmony_ci      Column() {
24e41f4b71Sopenharmony_ci        Column() {
25e41f4b71Sopenharmony_ci          Text(this.routerDetail)
26e41f4b71Sopenharmony_ci            .fontColor('#FFFFFF')
27e41f4b71Sopenharmony_ci            .opacity(0.9)
28e41f4b71Sopenharmony_ci            .fontSize(14)
29e41f4b71Sopenharmony_ci            .margin({ top: '8%', left: '10%', right: '10%' })
30e41f4b71Sopenharmony_ci            .textOverflow({ overflow: TextOverflow.Ellipsis })
31e41f4b71Sopenharmony_ci            .maxLines(2)
32e41f4b71Sopenharmony_ci        }.width('100%').height('50%')
33e41f4b71Sopenharmony_ci        .alignItems(HorizontalAlign.Start)
34e41f4b71Sopenharmony_ci  
35e41f4b71Sopenharmony_ci        Row() {
36e41f4b71Sopenharmony_ci          Button() {
37e41f4b71Sopenharmony_ci            Text($r('app.string.JumpLabel'))
38e41f4b71Sopenharmony_ci              .fontColor('#45A6F4')
39e41f4b71Sopenharmony_ci              .fontSize(12)
40e41f4b71Sopenharmony_ci          }
41e41f4b71Sopenharmony_ci          .width(120)
42e41f4b71Sopenharmony_ci          .height(32)
43e41f4b71Sopenharmony_ci          .margin({ top: '30%', bottom: '10%' })
44e41f4b71Sopenharmony_ci          .backgroundColor('#FFFFFF')
45e41f4b71Sopenharmony_ci          .borderRadius(16)
46e41f4b71Sopenharmony_ci          .onClick(() => {
47e41f4b71Sopenharmony_ci            postCardAction(this, {
48e41f4b71Sopenharmony_ci              action: 'router',
49e41f4b71Sopenharmony_ci              abilityName: 'WidgetEventRouterEntryAbility', // Only the UIAbility of the current application is allowed.
50e41f4b71Sopenharmony_ci              params: {
51e41f4b71Sopenharmony_ci                routerDetail: 'RouterFromCard',
52e41f4b71Sopenharmony_ci              }
53e41f4b71Sopenharmony_ci            });
54e41f4b71Sopenharmony_ci          })
55e41f4b71Sopenharmony_ci        }.width('100%').height('40%')
56e41f4b71Sopenharmony_ci        .justifyContent(FlexAlign.Center)
57e41f4b71Sopenharmony_ci      }
58e41f4b71Sopenharmony_ci      .width('100%')
59e41f4b71Sopenharmony_ci      .height('100%')
60e41f4b71Sopenharmony_ci      .alignItems(HorizontalAlign.Start)
61e41f4b71Sopenharmony_ci      .backgroundImage($r('app.media.CardEvent'))
62e41f4b71Sopenharmony_ci      .backgroundImageSize(ImageSize.Cover)
63e41f4b71Sopenharmony_ci    }
64e41f4b71Sopenharmony_ci  }
65e41f4b71Sopenharmony_ci  ```
66e41f4b71Sopenharmony_ci  
67e41f4b71Sopenharmony_ci- In the **onCreate** or **onNewWant** lifecycle callback of the UIAbility, use the input parameter **want** to obtain the ID (**formID**) and other information of the widget, and then call the [updateForm](../reference/apis-form-kit/js-apis-app-form-formProvider.md#updateform) API to update the widget.
68e41f4b71Sopenharmony_ci  
69e41f4b71Sopenharmony_ci  ```ts
70e41f4b71Sopenharmony_ci  import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
71e41f4b71Sopenharmony_ci  import { window } from '@kit.ArkUI';
72e41f4b71Sopenharmony_ci  import { BusinessError } from '@kit.BasicServicesKit';
73e41f4b71Sopenharmony_ci  import { formBindingData, formInfo, formProvider } from '@kit.FormKit';
74e41f4b71Sopenharmony_ci  import { hilog } from '@kit.PerformanceAnalysisKit';
75e41f4b71Sopenharmony_ci
76e41f4b71Sopenharmony_ci  const TAG: string = 'WidgetEventRouterEntryAbility';
77e41f4b71Sopenharmony_ci  const DOMAIN_NUMBER: number = 0xFF00;
78e41f4b71Sopenharmony_ci
79e41f4b71Sopenharmony_ci  export default class WidgetEventRouterEntryAbility extends UIAbility {
80e41f4b71Sopenharmony_ci    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
81e41f4b71Sopenharmony_ci      this.handleFormRouterEvent(want, 'onCreate');
82e41f4b71Sopenharmony_ci    }
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ci    handleFormRouterEvent(want: Want, source: string): void {
85e41f4b71Sopenharmony_ci      hilog.info(DOMAIN_NUMBER, TAG, `handleFormRouterEvent ${source}, Want: ${JSON.stringify(want)}`);
86e41f4b71Sopenharmony_ci      if (want.parameters && want.parameters[formInfo.FormParam.IDENTITY_KEY] !== undefined) {
87e41f4b71Sopenharmony_ci        let curFormId = want.parameters[formInfo.FormParam.IDENTITY_KEY].toString();
88e41f4b71Sopenharmony_ci        // want.parameters.params corresponds to params in postCardAction().
89e41f4b71Sopenharmony_ci        let message: string = (JSON.parse(want.parameters?.params as string))?.routerDetail;
90e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, `UpdateForm formId: ${curFormId}, message: ${message}`);
91e41f4b71Sopenharmony_ci        let formData: Record<string, string> = {
92e41f4b71Sopenharmony_ci          'routerDetail': message + ' ' + source + ' UIAbility', // It matches the widget layout.
93e41f4b71Sopenharmony_ci        };
94e41f4b71Sopenharmony_ci        let formMsg = formBindingData.createFormBindingData(formData);
95e41f4b71Sopenharmony_ci        formProvider.updateForm(curFormId, formMsg).then((data) => {
96e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, 'updateForm success.', JSON.stringify(data));
97e41f4b71Sopenharmony_ci        }).catch((error: BusinessError) => {
98e41f4b71Sopenharmony_ci          hilog.info(DOMAIN_NUMBER, TAG, 'updateForm failed.', JSON.stringify(error));
99e41f4b71Sopenharmony_ci        });
100e41f4b71Sopenharmony_ci      }
101e41f4b71Sopenharmony_ci    }
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci    // If the UIAbility is running in the background, onNewWant is triggered after the router event is received.
104e41f4b71Sopenharmony_ci    onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
105e41f4b71Sopenharmony_ci      hilog.info(DOMAIN_NUMBER, TAG, 'onNewWant Want:', JSON.stringify(want));
106e41f4b71Sopenharmony_ci      this.handleFormRouterEvent(want, 'onNewWant');
107e41f4b71Sopenharmony_ci    }
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci    onWindowStageCreate(windowStage: window.WindowStage): void {
110e41f4b71Sopenharmony_ci      // Main window is created, set main page for this ability
111e41f4b71Sopenharmony_ci      hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate');
112e41f4b71Sopenharmony_ci
113e41f4b71Sopenharmony_ci      windowStage.loadContent('pages/Index', (err, data) => {
114e41f4b71Sopenharmony_ci        if (err.code) {
115e41f4b71Sopenharmony_ci          hilog.error(DOMAIN_NUMBER, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
116e41f4b71Sopenharmony_ci          return;
117e41f4b71Sopenharmony_ci        }
118e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
119e41f4b71Sopenharmony_ci      });
120e41f4b71Sopenharmony_ci    }
121e41f4b71Sopenharmony_ci    // ...
122e41f4b71Sopenharmony_ci  }
123e41f4b71Sopenharmony_ci  ```
124e41f4b71Sopenharmony_ci
125e41f4b71Sopenharmony_ci
126e41f4b71Sopenharmony_ci## Updating Widget Content Through the call Event
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ci- When using the call event of the **postCardAction** API, the value of **formId** must be updated in the **onAddForm** callback of the FormExtensionAbility.
129e41f4b71Sopenharmony_ci
130e41f4b71Sopenharmony_ci  ```ts
131e41f4b71Sopenharmony_ci  import { Want } from '@kit.AbilityKit';
132e41f4b71Sopenharmony_ci  import { formBindingData, FormExtensionAbility } from '@kit.FormKit';
133e41f4b71Sopenharmony_ci  
134e41f4b71Sopenharmony_ci  export default class WidgetCalleeFormAbility extends FormExtensionAbility {
135e41f4b71Sopenharmony_ci    onAddForm(want: Want): formBindingData.FormBindingData {
136e41f4b71Sopenharmony_ci      class DataObj1 {
137e41f4b71Sopenharmony_ci        formId: string = '';
138e41f4b71Sopenharmony_ci      }
139e41f4b71Sopenharmony_ci  
140e41f4b71Sopenharmony_ci      let dataObj1 = new DataObj1();
141e41f4b71Sopenharmony_ci      if (want.parameters && want.parameters['ohos.extra.param.key.form_identity'] !== undefined) {
142e41f4b71Sopenharmony_ci        let formId: string = want.parameters['ohos.extra.param.key.form_identity'].toString();
143e41f4b71Sopenharmony_ci        dataObj1.formId = formId;
144e41f4b71Sopenharmony_ci      }
145e41f4b71Sopenharmony_ci      let obj1 = formBindingData.createFormBindingData(dataObj1);
146e41f4b71Sopenharmony_ci      return obj1;
147e41f4b71Sopenharmony_ci    }
148e41f4b71Sopenharmony_ci    // ...
149e41f4b71Sopenharmony_ci  }
150e41f4b71Sopenharmony_ci  ```
151e41f4b71Sopenharmony_ci
152e41f4b71Sopenharmony_ci- On the widget page, register the **onClick** event callback of the button and call the **postCardAction** API in the callback to trigger the call event to start the UIAbility.
153e41f4b71Sopenharmony_ci  
154e41f4b71Sopenharmony_ci  ```ts
155e41f4b71Sopenharmony_ci  let storageUpdateCall = new LocalStorage();
156e41f4b71Sopenharmony_ci  
157e41f4b71Sopenharmony_ci  @Entry(storageUpdateCall)
158e41f4b71Sopenharmony_ci  @Component
159e41f4b71Sopenharmony_ci  struct WidgetUpdateCallCard {
160e41f4b71Sopenharmony_ci    @LocalStorageProp('formId') formId: string = '12400633174999288';
161e41f4b71Sopenharmony_ci    @LocalStorageProp('calleeDetail') calleeDetail: ResourceStr = $r('app.string.init');
162e41f4b71Sopenharmony_ci  
163e41f4b71Sopenharmony_ci    build() {
164e41f4b71Sopenharmony_ci      Column() {
165e41f4b71Sopenharmony_ci        Column() {
166e41f4b71Sopenharmony_ci            Text(this.calleeDetail)
167e41f4b71Sopenharmony_ci            .fontColor('#FFFFFF')
168e41f4b71Sopenharmony_ci            .opacity(0.9)
169e41f4b71Sopenharmony_ci            .fontSize(14)
170e41f4b71Sopenharmony_ci            .margin({ top: '8%', left: '10%' })
171e41f4b71Sopenharmony_ci        }.width('100%').height('50%')
172e41f4b71Sopenharmony_ci        .alignItems(HorizontalAlign.Start)
173e41f4b71Sopenharmony_ci  
174e41f4b71Sopenharmony_ci        Row() {
175e41f4b71Sopenharmony_ci          Button() {
176e41f4b71Sopenharmony_ci            Text($r('app.string.CalleeJumpLabel'))
177e41f4b71Sopenharmony_ci              .fontColor('#45A6F4')
178e41f4b71Sopenharmony_ci              .fontSize(12)
179e41f4b71Sopenharmony_ci          }
180e41f4b71Sopenharmony_ci          .width(120)
181e41f4b71Sopenharmony_ci          .height(32)
182e41f4b71Sopenharmony_ci          .margin({ top: '30%', bottom: '10%' })
183e41f4b71Sopenharmony_ci          .backgroundColor('#FFFFFF')
184e41f4b71Sopenharmony_ci          .borderRadius(16)
185e41f4b71Sopenharmony_ci          .onClick(() => {
186e41f4b71Sopenharmony_ci            postCardAction(this, {
187e41f4b71Sopenharmony_ci              action: 'call',
188e41f4b71Sopenharmony_ci              abilityName: 'WidgetCalleeEntryAbility', // Only the UIAbility of the current application is allowed.
189e41f4b71Sopenharmony_ci              params: {
190e41f4b71Sopenharmony_ci                method: 'funA',
191e41f4b71Sopenharmony_ci                formId: this.formId,
192e41f4b71Sopenharmony_ci                calleeDetail: 'CallFrom'
193e41f4b71Sopenharmony_ci              }
194e41f4b71Sopenharmony_ci            });
195e41f4b71Sopenharmony_ci          })
196e41f4b71Sopenharmony_ci        }.width('100%').height('40%')
197e41f4b71Sopenharmony_ci        .justifyContent(FlexAlign.Center)
198e41f4b71Sopenharmony_ci      }
199e41f4b71Sopenharmony_ci      .width('100%')
200e41f4b71Sopenharmony_ci      .height('100%')
201e41f4b71Sopenharmony_ci      .alignItems(HorizontalAlign.Start)
202e41f4b71Sopenharmony_ci      .backgroundImage($r('app.media.CardEvent'))
203e41f4b71Sopenharmony_ci      .backgroundImageSize(ImageSize.Cover)
204e41f4b71Sopenharmony_ci    }
205e41f4b71Sopenharmony_ci  }
206e41f4b71Sopenharmony_ci  ```
207e41f4b71Sopenharmony_ci  
208e41f4b71Sopenharmony_ci- Listen for the method required by the call event in the **onCreate** callback of the UIAbility, and then call the [updateForm](../reference/apis-form-kit/js-apis-app-form-formProvider.md#updateform) API in the corresponding method to update the widget.
209e41f4b71Sopenharmony_ci  
210e41f4b71Sopenharmony_ci  ```ts
211e41f4b71Sopenharmony_ci  import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
212e41f4b71Sopenharmony_ci  import { window } from '@kit.ArkUI';
213e41f4b71Sopenharmony_ci  import { BusinessError } from '@kit.BasicServicesKit';
214e41f4b71Sopenharmony_ci  import { formBindingData, formProvider } from '@kit.FormKit';
215e41f4b71Sopenharmony_ci  import { rpc } from '@kit.IPCKit';
216e41f4b71Sopenharmony_ci  import { hilog } from '@kit.PerformanceAnalysisKit';
217e41f4b71Sopenharmony_ci  
218e41f4b71Sopenharmony_ci  const TAG: string = 'WidgetCalleeEntryAbility';
219e41f4b71Sopenharmony_ci  const DOMAIN_NUMBER: number = 0xFF00;
220e41f4b71Sopenharmony_ci  const MSG_SEND_METHOD: string = 'funA';
221e41f4b71Sopenharmony_ci  const CONST_NUMBER_1: number = 1;
222e41f4b71Sopenharmony_ci  
223e41f4b71Sopenharmony_ci  class MyParcelable implements rpc.Parcelable {
224e41f4b71Sopenharmony_ci    num: number;
225e41f4b71Sopenharmony_ci    str: string;
226e41f4b71Sopenharmony_ci  
227e41f4b71Sopenharmony_ci    constructor(num: number, str: string) {
228e41f4b71Sopenharmony_ci      this.num = num;
229e41f4b71Sopenharmony_ci      this.str = str;
230e41f4b71Sopenharmony_ci    };
231e41f4b71Sopenharmony_ci  
232e41f4b71Sopenharmony_ci    marshalling(messageSequence: rpc.MessageSequence): boolean {
233e41f4b71Sopenharmony_ci      messageSequence.writeInt(this.num);
234e41f4b71Sopenharmony_ci      messageSequence.writeString(this.str);
235e41f4b71Sopenharmony_ci      return true;
236e41f4b71Sopenharmony_ci    };
237e41f4b71Sopenharmony_ci  
238e41f4b71Sopenharmony_ci    unmarshalling(messageSequence: rpc.MessageSequence): boolean {
239e41f4b71Sopenharmony_ci      this.num = messageSequence.readInt();
240e41f4b71Sopenharmony_ci      this.str = messageSequence.readString();
241e41f4b71Sopenharmony_ci      return true;
242e41f4b71Sopenharmony_ci    };
243e41f4b71Sopenharmony_ci  }
244e41f4b71Sopenharmony_ci  
245e41f4b71Sopenharmony_ci  // After the call event is received, the method listened for by the callee is triggered.
246e41f4b71Sopenharmony_ci  let funACall = (data: rpc.MessageSequence): MyParcelable => {
247e41f4b71Sopenharmony_ci    // Obtain all parameters transferred in the call event.
248e41f4b71Sopenharmony_ci    let params: Record<string, string> = JSON.parse(data.readString());
249e41f4b71Sopenharmony_ci    if (params.formId !== undefined) {
250e41f4b71Sopenharmony_ci      let curFormId: string = params.formId;
251e41f4b71Sopenharmony_ci      let message: string = params.calleeDetail;
252e41f4b71Sopenharmony_ci      hilog.info(DOMAIN_NUMBER, TAG, `UpdateForm formId: ${curFormId}, message: ${message}`);
253e41f4b71Sopenharmony_ci      let formData: Record<string, string> = {
254e41f4b71Sopenharmony_ci        'calleeDetail': message
255e41f4b71Sopenharmony_ci      };
256e41f4b71Sopenharmony_ci      let formMsg: formBindingData.FormBindingData = formBindingData.createFormBindingData(formData);
257e41f4b71Sopenharmony_ci      formProvider.updateForm(curFormId, formMsg).then((data) => {
258e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, `updateForm success. ${JSON.stringify(data)}`);
259e41f4b71Sopenharmony_ci      }).catch((error: BusinessError) => {
260e41f4b71Sopenharmony_ci        hilog.error(DOMAIN_NUMBER, TAG, `updateForm failed: ${JSON.stringify(error)}`);
261e41f4b71Sopenharmony_ci      });
262e41f4b71Sopenharmony_ci    }
263e41f4b71Sopenharmony_ci    return new MyParcelable(CONST_NUMBER_1, 'aaa');
264e41f4b71Sopenharmony_ci  };
265e41f4b71Sopenharmony_ci  
266e41f4b71Sopenharmony_ci  export default class WidgetCalleeEntryAbility extends UIAbility {
267e41f4b71Sopenharmony_ci    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
268e41f4b71Sopenharmony_ci      try {
269e41f4b71Sopenharmony_ci        // Listen for the method required by the call event.
270e41f4b71Sopenharmony_ci        this.callee.on(MSG_SEND_METHOD, funACall);
271e41f4b71Sopenharmony_ci      } catch (error) {
272e41f4b71Sopenharmony_ci        hilog.error(DOMAIN_NUMBER, TAG, `${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`);
273e41f4b71Sopenharmony_ci      }
274e41f4b71Sopenharmony_ci    }
275e41f4b71Sopenharmony_ci  
276e41f4b71Sopenharmony_ci    onWindowStageCreate(windowStage: window.WindowStage): void {
277e41f4b71Sopenharmony_ci      // Main window is created, set main page for this ability
278e41f4b71Sopenharmony_ci      hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onWindowStageCreate');
279e41f4b71Sopenharmony_ci  
280e41f4b71Sopenharmony_ci      windowStage.loadContent('pages/Index', (err, data) => {
281e41f4b71Sopenharmony_ci        if (err.code) {
282e41f4b71Sopenharmony_ci          hilog.error(DOMAIN_NUMBER, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
283e41f4b71Sopenharmony_ci          return;
284e41f4b71Sopenharmony_ci        }
285e41f4b71Sopenharmony_ci        hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
286e41f4b71Sopenharmony_ci      });
287e41f4b71Sopenharmony_ci    }
288e41f4b71Sopenharmony_ci  }
289e41f4b71Sopenharmony_ci  ```
290