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