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