1# Updating Widget Content by State 2 3There are cases where multiple copies of the same widget are added to the home screen to accommodate different needs. In these cases, the widget content needs to be dynamically updated based on the state. This topic exemplifies how this is implemented. 4 5In the following example, two copies of the weather widget are added to the home screen: one for displaying the weather of London, and the other Beijing, both configured to be updated at 07:00 every morning. The widget provider detects the target city, and then displays the city-specific weather information on the widgets. 6 7 8- Widget configuration file: Configure the widget to be updated at 07:00 every morning. 9 10 ```json 11 { 12 "forms": [ 13 { 14 "name": "widget", 15 "description": "This is a service widget.", 16 "src": "./ets/widget/pages/WidgetCard.ets", 17 "uiSyntax": "arkts", 18 "window": { 19 "designWidth": 720, 20 "autoDesignWidth": true 21 }, 22 "colorMode": "auto", 23 "isDefault": true, 24 "updateEnabled": true, 25 "scheduledUpdateTime": "07:00", 26 "updateDuration": 0, 27 "defaultDimension": "2*2", 28 "supportDimensions": ["2*2"] 29 } 30 ] 31 } 32 ``` 33 34- Widget page: A widget has different states and needs to be updated by state. When the state changes, **postCardAction** is called to notify the EntryFormAbility. 35 36 ```ts 37 let storage = new LocalStorage(); 38 @Entry(storage) 39 @Component 40 struct WidgetCard { 41 @LocalStorageProp('textA') textA: string = 'To be updated...'; 42 @LocalStorageProp('textB') textB: string ='To be updated...'; 43 @State selectA: boolean = false; 44 @State selectB: boolean = false; 45 46 build() { 47 Column() { 48 Row() { 49 Checkbox({ name: 'checkbox1', group: 'checkboxGroup' }) 50 .select(false) 51 .onChange((value: boolean) => { 52 this.selectA = value; 53 postCardAction(this, { 54 'action': 'message', 55 'params': { 56 'selectA': JSON.stringify(value) 57 } 58 }); 59 }) 60 Text ('State A') 61 } 62 63 Row() { 64 Checkbox({ name: 'checkbox2', group: 'checkboxGroup' }) 65 .select(false) 66 .onChange((value: boolean) => { 67 this.selectB = value; 68 postCardAction(this, { 69 'action': 'message', 70 'params': { 71 'selectB': JSON.stringify(value) 72 } 73 }); 74 }) 75 Text ('State B') 76 } 77 78 Row() {// Content that is updated only in state A 79 Text ('State A:') 80 Text(this.textA) 81 } 82 83 Row() { // Content that is updated only in state B 84 Text ('State B:') 85 Text(this.textB) 86 } 87 }.padding('10%') 88 } 89 } 90 ``` 91 92- EntryFormAbility: The widget state data is stored in the local database. When the update event callback is triggered, the current widget state is obtained through **formId**, and then content is updated based on the state obtained. 93 94 ```ts 95 import formInfo from '@ohos.app.form.formInfo' 96 import formProvider from '@ohos.app.form.formProvider'; 97 import formBindingData from '@ohos.app.form.formBindingData'; 98 import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility'; 99 import dataPreferences from '@ohos.data.preferences'; 100 import Want from '@ohos.app.ability.Want'; 101 import Base from '@ohos.base'; 102 103 export default class EntryFormAbility extends FormExtensionAbility { 104 onAddForm(want: Want) { 105 let formId: string = ''; 106 let isTempCard: boolean; 107 if (want.parameters) { 108 formId = JSON.stringify(want.parameters[formInfo.FormParam.IDENTITY_KEY]); 109 isTempCard = want.parameters[formInfo.FormParam.TEMPORARY_KEY] as boolean; 110 if (isTempCard === false) {// If the widget is a normal one, the widget information is persisted. 111 console.info('Not temp card, init db for:' + formId); 112 let promise: Promise<dataPreferences.Preferences> = dataPreferences.getPreferences(this.context, 'myStore'); 113 promise.then(async (storeDB: dataPreferences.Preferences) => { 114 console.info("Succeeded to get preferences."); 115 await storeDB.put('A' + formId, 'false'); 116 await storeDB.put('B' + formId, 'false'); 117 await storeDB.flush(); 118 }).catch((err: Base.BusinessError) => { 119 console.info(`Failed to get preferences. ${JSON.stringify(err)}`); 120 }) 121 } 122 } 123 let formData: Record<string, Object | string> = {}; 124 return formBindingData.createFormBindingData(formData); 125 } 126 127 onRemoveForm(formId: string) { 128 console.info('onRemoveForm, formId:' + formId); 129 let promise = dataPreferences.getPreferences(this.context, 'myStore'); 130 promise.then(async (storeDB) => { 131 console.info("Succeeded to get preferences."); 132 await storeDB.delete('A' + formId); 133 await storeDB.delete('B' + formId); 134 }).catch((err: Base.BusinessError) => { 135 console.info(`Failed to get preferences. ${JSON.stringify(err)}`); 136 }) 137 } 138 139 // If the widget is a temporary one, it is recommended that the widget information be persisted when the widget is converted to a normal one. 140 onCastToNormalForm(formId: string) { 141 console.info('onCastToNormalForm, formId:' + formId); 142 let promise: Promise<dataPreferences.Preferences> = dataPreferences.getPreferences(this.context, 'myStore'); 143 promise.then(async (storeDB: dataPreferences.Preferences) => { 144 console.info("Succeeded to get preferences."); 145 await storeDB.put('A' + formId, 'false'); 146 await storeDB.put('B' + formId, 'false'); 147 await storeDB.flush(); 148 }).catch((err: Base.BusinessError) => { 149 console.info(`Failed to get preferences. ${JSON.stringify(err)}`); 150 }) 151 } 152 153 onUpdateForm(formId: string) { 154 let promise: Promise<dataPreferences.Preferences> = dataPreferences.getPreferences(this.context, 'myStore'); 155 promise.then(async (storeDB: dataPreferences.Preferences) => { 156 console.info("Succeeded to get preferences."); 157 let stateA = await storeDB.get('A' + formId, 'false'); 158 let stateB = await storeDB.get('B' + formId, 'false'); 159 // Update textA in state A. 160 if (stateA === 'true') { 161 let param: Record<string, string> = { 'textA': 'AAA' }; 162 let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(param); 163 await formProvider.updateForm(formId, formInfo); 164 } 165 // Update textB in state B. 166 if (stateB === 'true') { 167 let param: Record<string, string> = { 'textB': 'BBB' }; 168 let formInfo: formBindingData.FormBindingData = formBindingData.createFormBindingData(param); 169 await formProvider.updateForm(formId, formInfo); 170 } 171 console.info(`Update form success stateA:${stateA} stateB:${stateB}.`); 172 }).catch((err: Base.BusinessError) => { 173 console.info(`Failed to get preferences. ${JSON.stringify(err)}`); 174 }) 175 } 176 177 onFormEvent(formId: string, message: string) { 178 // Store the widget state. 179 console.info('onFormEvent formId:' + formId + 'msg:' + message); 180 let promise: Promise<dataPreferences.Preferences> = dataPreferences.getPreferences(this.context, 'myStore'); 181 promise.then(async (storeDB: dataPreferences.Preferences) => { 182 console.info("Succeeded to get preferences."); 183 let msg: Record<string, string> = JSON.parse(message); 184 if (msg.selectA != undefined) { 185 console.info('onFormEvent selectA info:' + msg.selectA); 186 await storeDB.put('A' + formId, msg.selectA); 187 } 188 if (msg.selectB != undefined) { 189 console.info('onFormEvent selectB info:' + msg.selectB); 190 await storeDB.put('B' + formId, msg.selectB); 191 } 192 await storeDB.flush(); 193 }).catch((err: Base.BusinessError) => { 194 console.info(`Failed to get preferences. ${JSON.stringify(err)}`); 195 }) 196 } 197 }; 198 ``` 199 200 201> **NOTE** 202> 203> When the local database is used for widget information persistence, it is recommended that [TEMPORARY_KEY](../reference/apis/js-apis-app-form-formInfo.md#formparam) be used in the [onAddForm](../reference/apis/js-apis-app-form-formExtensionAbility.md#onaddform) lifecycle callback to determine whether the currently added widget is a normal one. If the widget is a normal one, the widget information is directly persisted. If the widget is a temporary one, the widget information is persisted when the widget is converted to a normal one ([onCastToNormalForm](../reference/apis/js-apis-app-form-formExtensionAbility.md#oncasttonormalform)). In addition, the persistent widget information needs to be deleted when the widget is destroyed ([onRemoveForm](../reference/apis/js-apis-app-form-formExtensionAbility.md#onremoveform)), preventing the database size from continuously increasing due to repeated widget addition and deletion. 204