Persist data to Storage
Description
If enabled, persists the List's data to client-side storage. Storage options include Local Storage, device Filesystem (Mobile apps only), and IndexedDB. This option is typically checked when creating an application that that needs to work without an internet connection (offline).
To build an application for disconnected operation, the data in the application needs to is persisted to client-side storage to ensure edits to data are preserved if the application restarts or closes before the user has a chance to save changes to the server. Enabling Persist data to Storage adds offline support to the List control.
When Persist data to Storage is enabled, the List control automatically stores it's data to client-side storage, such as Local Storage, IndexedDB, or the device File System (mobile only).
In order to restore List data from Local Storage you must also check the Restore data in List controls from Local Storage property in the 'Local Storage' section on the 'Properties' pane of the UX Builder. For a guide on using Restore data in List controls from Local Storage, see Persisting Data to Local Storage.
Using IndexedDB to Persist List data
IndexedDB is a NoSQL data store available in most modern web browsers. Data is stored in IndexedDB as key-value pairs. IndexedDB is similar to Local Storage in that it's a client-side storage where you can persist application data beyond the duration of a browser session. IndexedDB offers several advantages over Local Storage, making IndexedDB the preferred method of storing data in the client:
- IndexedDB actions are asynchronous. This means IndexedDB operations do not block the main JavaScript thread. Promises or callbacks are used instead to continue processing once an operation completes.
- IndexedDB actions are transactioned. This ensures that your operations will complete even if the user opens your app in multiple browser tabs.
- Significantly more storage space -- 1GB or more depending on the browser. Local Storage is limited to 5MB.
- Data persisted for a long time and more reliably than Local Storage. Though browser dependent, the scope in which an IndexedDB database will be deleted is more constrained than Local Storage.
- Any type of data (string, blob, array, etc) can be stored. Local Storage only supports storing strings.
Data in an IndexedDB database is protected by the same origin policy. This means that data stored to IndexedDB by a web site can only be retrieved by the same site. This applies to both the domain and protocol -- HTTP and HTTPS versions of the same domain (e.g. www.example.com) cannot access the other's IndexedDB data.
Be aware that IndexedDB data can be accessed through the browser's debugging tools (such as Chrome Debugger) and the raw values read. If you store information in IndexedDB, users can access it through the browser tools. This is also true for storing data in Local Storage.
To persist a List's data to IndexedDB, set the Persist list data where property to IndexedDB. If IndexedDB is available on the device where the app is running, the List data and edits will be stored in IndexedDB. If IndexedDB is not available, the List will persist to Local Storage. Persisting to IndexedDB is recommend for web applications, mobile web apps, and progressive web apps.
If you are building a Cordova or Alpha Launch app, it's recommended that you persist List data to the File System.
Using the File System to Persist List data
When you build a mobile app that is intended to operate offline, the typical pattern is to use List controls with Detail Views and to turn on the option to persist the List data to storage.
In web applications, data in the List can be persisted to the browser's Local Storage or IndexedDB (if supported). Local storage is limited to 5mb of space. IndexedDB can store far more information (at least 1 GB, more depending on the browser), however not all browsers support IndexedDB. See caniuse for information on browser support for IndexedDB.
In mobile applications, data can be persisted to Local Storage, File System, or IndexedDB (if supported by the device). Persisting data to the File System allows you to work with more than 5MB of data in mobile applications when the device is offline.
To turn on the feature to persist List data to the File System, set the Persist where property to FileSystem.
If you set Persist where to LocalStorage, you can set the Persist mode to either 'Full', or 'Edits'.
In 'Full' mode, each time the data in the List are edited, the entire List is persisted to Local Storage.
In 'Edits' mode, each time the data in the List are edited, only the edited rows are persisted to Local Storage.
If you set the Persist where option to FileSystem or IndexedDB, the Persist mode option is not available.
How Persisting Data to the File System Works
When you persist List data to Local Storage, when the List is initially populated the List data is persisted to Local Storage. Each time the List data are edited, the entire List is persisted again to Local Storage (unless you change the Persist mode option to Edits). Because writing to Local Storage is so fast, and because there is a built-in limit (of approximately 5mb) to the amount of data that must be written to Local Storage on each edit, there is no perceptible delay when you are editing the data in the List.
However, writing to the File System is much slower than writing to Local Storage and because there is no longer a built-in limit as to the amount of data in the List, a different approach is taken when the FileSystem option is used. When the List is initially populated, all of the data in the List are written to a file in the File System. Each time the List is edited, the only the rows in the List that have been edited are written to a second file in the File System. This will file will typically be substantially smaller than the first file (that contains all of the List data), and since the file is likely very small, writing this file to the File System will be very fast, and again, there will be no perceptible delay when you are editing data in the List.
When the List is synchronized data in the synced rows are written to a third file in the File System and the primary keys of any deleted rows are written to a fourth file in the File System.
The filenames of these four files in the File System are:
- <namespace>.LIST.<listName>
The file that contains all of the List data. This file is only written to when the List is initially populated or refreshed. This file can be quite large (several megabytes) - much larger than would be allowed in Local Storage.
- <namespace>.LISTEDITS.<listName>
The file that contains the rows in the List that have been edited, but not yet synced. This file is updated each time the user makes an edit to the List data. This file is typically quite small.
- <namespace>.LISTSYNCEDEDITS.<listName>
The file that contains the rows in the List that have been edited and synced. This file is updated after the user had synced the List data. This file is typically quite small.
- <namespace>.LISTSYNCEDDELETES.<listName>
The file that contains the primary keys of the rows in the List that have been deleted. This file is updated after the user had synced the List data. This file is typically quite small.
Where:
- <listName>
The Id of the List.
- <namespace>
The value of the Namespace property (see image below).
If the List is persisted to Local Storage, the Namespace property is used to generate the Local Storage key name. If List data is persisted to the File System, the Namespace property is used to generate filenames for the four files used to persist data and edits.Location of the List Data Files in the File System
The files for the List data are stored in the device's 'saved' File System. The location of the device's 'saved' File System is returned by the {dialog.object}.phoneGapGetLocalDirURL('saved') method. The files are stored in a directory (called _offline by default) in this location.
The following methods can be use to get the File System URL and folder for the List data files:
- {dialog.object}._persistFS()
The File System URL of the directory in which the List data sub-directory is located
- {dialog.object}._persistFolder()
The sub-folder in which the files are actually stored - name has a trailing / character.
The actual folder name of the files is therefore:
{dialog.object}._persistFS() + {dialog.object}._persistFolder()
For example, the fully qualified name of the file that contains all of the data in the List when the list is initially populated is therefore (assuming the List id is LIST1 and the UX Local Storage Namespace property was set to NS1):
{dialog.object}._persistFS() + {dialog.object}._persistFolder() + 'NS1.LIST.LIST1'
In the case where the component is running in AlphaLaunch, the base folder for the files is in a special folder returned by the A5.shell.getAppFileStorageDir() method. The {dialog.object}._persistFS() will return the appropriate base folder name when the component is running in AlphaLaunch.List Virtualization
If you are populating a List with a large amount of data, it is strongly recommended that you turn on the List's virtualization feature. With virtualization turned on, populating a List with a large amount of data is substantially faster than populating the List with virtualization turned off.
To turn on List virtualization, set the Virtualization type property to Dynamic as shown in the image below.
Persisting Data to Local Storage
Defining a UX List Control that can use 'Persist Data to Local Storage (or Filesystem)'
In order to use this property it is necessary to first create the updatable list control to which it can be applied.
Open the UX Builder. On the UX Controls page view the Data Controls menu and click the [Textbox] option to add a textbox control to the component. Give the control the name 'search'.
Create five additional text box controls on the component. Give these the names city, contact, address, country, and company. Your control pageshould look something like this:
In the Data Controls menu and double click the [List] option to add a list control to the component.
Highlight the list control. In the control's properties list on the right find the List Properties. Click the button next to the 'List properties' property to open the list builder.
Open the 'Data Source' pane of the list builder. In the Data Source Type menu select SQL
Under SQL Data Source, set the Connection string property to the Northwind database. Set the Table name property to the Customers table. After doing this click the button next to the "Field list" property and select the ContactName, CompanyName, City, Country, and Address fields.
In the Return Value section of the Data Source page, set the Return value type to 'PrimaryKey'.
Open the List Layout pane. Use the blue > arrow to move the fields that you just added from the 'Available fields' list to the 'Columns in list'
Open the Properties pane. Place a check next to both the 'Has Detail View' property and the 'Has Search Part' property.
Open the 'Detail View' pane. Under Detail View Properties make sure the Detail view type is set to FieldMap, then click the button next to the Detail view field map property.
In the Define Field Map dialog click on each field and then click on the 'Map Field'' button. Select the textbox control name that corresponds to the field name and click OK. Repeat this process for all five fields.
The Auto-map Fields button will speed this process upNow click the Detail View - Quick Setup Genie button at the bottom of the Detail View Pane.
Check "Add buttons to the List Detail View to perform actions such as 'Save edits', Synchronize data', 'etc.'". Then check the 'Create buttons for most commonly used actions' option. Click OK.
Add the button controls to the end of the component.
Click OK to get back to the List Builder.
Open the Search Part. Under Search Part Style click the dropdown control next to the Search Part style property. Choose the 'SingleKeywordControl' option.
Click the button next to the 'Keyword search fields' property. Check all five fields and click OK
Set the Keyword search control to be the 'search' textbox defined earlier.
On the Controls page go to the 'Defined Controls' and click the List-Search Part-Buttons option. To add this button to the component
The 'Select Buttons for the List's Search Part' will appear. Highlight the list control in the top menu and then check the 'Submit Search' option.
Move all of the controls into the following arrangement using the up and down blue arrows in the Controls page. You might need to add a container and turn off some toggles to make everything look alright in Working Preview.
Run in Working Preview.
Now click on one of the records. You should see the fields appear in the Detail View you defined. Make a change to one of the records and click the component's Save' button.
Close working preview by opening the 'Design pane'. Then re-open it. The changes you made should not appear in the updated record.
Using 'Persist Data to Local Storage (or Filesystem)'
Highlight the list control and reopen the List Builder from the List properties property.
Go to the List Builder's 'List Properties' pane. Check the Persist data to Local Storage (or Filesystem) checkbox. Click OK to close the List Builder.
Open the UX Properties page. Scroll down to the Local Storage Properties. Change the 'Namespace' property to be 'DEMO1
Check the 'Restore data in List controls from Local Storage property.
Run in Working Preview. Make some changes to a file and click the Save button in the component.
This time when you go to the design tab and then re-open the Working Preview page you should see your changes are still there.
Deleting Local Storage
Deleting the files that contain the List data can be useful when debugging an application. You can delete the files that contain the List data using this Javascript:
var ls = {dialog.object}._localStorageSettings; {dialog.object}._persistToLocalStorageInitializeKeys(ls,'listId',true);
See Also