• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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