• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Updating Widget Content by State
2
3
4There 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. In the following example, two weather widgets 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.
5
6
7- Widget configuration file: Configure the widget to be updated at 07:00 every morning.
8
9  ```json
10  {
11    "forms": [
12      {
13        "name": "widget",
14        "description": "This is a service widget.",
15        "src": "./ets/widget/pages/WidgetCard.ets",
16        "uiSyntax": "arkts",
17        "window": {
18          "designWidth": 720,
19          "autoDesignWidth": true
20        },
21        "colorMode": "auto",
22        "isDefault": true,
23        "updateEnabled": true,"scheduledUpdateTime": "07:00",
24        "updateDuration": 0,
25        "defaultDimension": "2*2",
26        "supportDimensions": ["2*2"]
27      }
28    ]
29  }
30  ```
31
32- 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.
33
34  ```ts
35  let storage = new LocalStorage();
36  @Entry(storage)
37  @Component
38  struct WidgetCard {
39    @LocalStorageProp('textA') textA: string = 'To be updated...';
40    @LocalStorageProp('textB') textB: string ='To be updated...';
41    @State selectA: boolean = false;
42    @State selectB: boolean = false;
43
44    build() {
45      Column() {
46        Row() {
47          Checkbox({ name: 'checkbox1', group: 'checkboxGroup' })
48            .select(false)
49            .onChange((value: boolean) => {
50              this.selectA = value;
51              postCardAction(this, {
52                'action': 'message',
53                'params': {
54                  'selectA': JSON.stringify(value)
55                }
56              });
57            })
58          Text ('State A')
59        }
60
61        Row() {
62          Checkbox({ name: 'checkbox2', group: 'checkboxGroup' })
63            .select(false)
64            .onChange((value: boolean) => {
65              this.selectB = value;
66              postCardAction(this, {
67                'action': 'message',
68                'params': {
69                  'selectB': JSON.stringify(value)
70                }
71              });
72            })
73          Text ('State B')
74        }
75
76        Row() {// Content that is updated only in state A
77          Text ('State A:')
78          Text(this.textA)
79        }
80
81        Row() { // Content that is updated only in state B
82          Text ('State B:')
83          Text(this.textB)
84        }
85      }.padding('10%')
86    }
87  }
88  ```
89
90- 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.
91
92  ```ts
93  import formInfo from '@ohos.app.form.formInfo'
94  import formProvider from '@ohos.app.form.formProvider';
95  import formBindingData from '@ohos.app.form.formBindingData';
96  import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
97  import dataStorage from '@ohos.data.storage'
98
99  export default class EntryFormAbility extends FormExtensionAbility {
100    onAddForm(want) {
101      let formId = want.parameters[formInfo.FormParam.IDENTITY_KEY];
102      let isTempCard: boolean = want.parameters[formInfo.FormParam.TEMPORARY_KEY];
103      if (isTempCard === false) {// If the widget is a normal one, the widget information is persisted.
104        console.info('Not temp card, init db for:' + formId);
105        let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
106        storeDB.putSync('A' + formId, 'false');
107        storeDB.putSync('B' + formId, 'false');
108        storeDB.flushSync();
109      }
110      let formData = {};
111      return formBindingData.createFormBindingData(formData);
112    }
113
114    onRemoveForm(formId) {
115      console.info('onRemoveForm, formId:' + formId);
116      let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
117      storeDB.deleteSync('A' + formId);
118      storeDB.deleteSync('B' + formId);
119    }
120
121    // 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.
122    onCastToNormalForm(formId) {
123      console.info('onCastToNormalForm, formId:' + formId);
124      let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
125      storeDB.putSync('A' + formId, 'false');
126      storeDB.putSync('B' + formId, 'false');
127      storeDB.flushSync();
128    }
129
130    onUpdateForm(formId) {
131      let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
132      let stateA = storeDB.getSync('A' + formId, 'false').toString()
133      let stateB = storeDB.getSync('B' + formId, 'false').toString()
134      // Update textA in state A.
135      if (stateA === 'true') {
136        let formInfo = formBindingData.createFormBindingData({
137          'textA': 'AAA'
138        })
139        formProvider.updateForm(formId, formInfo)
140      }
141      // Update textB in state B.
142      if (stateB === 'true') {
143        let formInfo = formBindingData.createFormBindingData({
144          'textB': 'BBB'
145        })
146        formProvider.updateForm(formId, formInfo)
147      }
148    }
149
150    onFormEvent(formId, message) {
151      // Store the widget state.
152      console.info('onFormEvent formId:' + formId + 'msg:' + message);
153      let storeDB = dataStorage.getStorageSync(this.context.filesDir + 'myStore')
154      let msg = JSON.parse(message)
155      if (msg.selectA != undefined) {
156        console.info('onFormEvent selectA info:' + msg.selectA);
157        storeDB.putSync('A' + formId, msg.selectA);
158      }
159      if (msg.selectB != undefined) {
160        console.info('onFormEvent selectB info:' + msg.selectB);
161        storeDB.putSync('B' + formId, msg.selectB);
162      }
163      storeDB.flushSync();
164    }
165  };
166  ```
167
168
169> **NOTE**
170>
171> 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 to determine whether the currently added widget is a normal one in the [onAddForm](../reference/apis/js-apis-app-form-formExtensionAbility.md#onaddform) lifecycle callback. 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.
172