A proxy view model for JSON data sources. More...
Import Statement: | import Felgo 4.0 |
Since: | Felgo 2.18.3 |
JsonListModel allows to transform your JSON data into a QML ListModel for usage with e.g. an AppListView.
With Felgo, you develop apps using QML and JavaScript. This makes it easy to work with JSON data and REST APIs, as you can see with the examples of the Access a REST Service topic. But JSON objects are a variant data type. This means that there's no defined data structure that default UI components can expect. When you use this variant type as your data source for e.g. an AppListView, the list view is not able to fully utilize all its features.
For example, if individual data properties or list entries in your JSON data are modified, the list view can not track these changes. Thus, each modification of the data requires to recreate and redraw the list from scratch. Of course this is not ideal in terms of performance and user experience.
In addition, advanced features like list sections or transition animations are not available. The JsonListModel solves all these issues. It integrates QSyncable, a ListModel implementation by Ben Lau. You can also find the full project on GitHub.
The JsonListModel holds a local copy of the specified JSON data. Whenever the source JSON data changes, it is compared to the local copy of the model. After diffing the two sets of data, the JsonListModel applies all detected changes individually. It thus synchronizes the local copy with the JSON data step-by-step.
The JsonListModel type implements the full QML ListModel API and fires individual events for all changes in the data. The list view can thus only update relevant entries or apply transition animations. This is super useful, as you can e.g. fetch new data and simply replace the old JSON. The JsonListModel will detect all changes, and the ListView updates its items accordingly - without a full redraw.
The JsonListModel is backed by a performant QSyncable model in Qt C++ and exposed to QML for easy usage. With the JsonListModel you can:
With the JsonListModel you do not require to implement a custom model in C++ anymore. The JsonListModel itself is your C++ model, which is fully usable from QML and can work with JSON list items of any format.
Apart from list views, the model also supports the GridView and Repeater types to display model data.
For a simple example project that uses JsonListModel to show data from a REST API, you can see the MVC Architecture Demo App.
The advanced ToDo List App supports fetching of todos, creation and storing of drafts, offline caching, paging, sorting and filtering. It uses list tranisition animations and shows how to integrate PullToRefreshHandler, VisibilityRefreshHandler or SortFilterProxyModel.
The following example shows how to use JsonListModel together with AppListView. When adding a new item to the JSON, the JsonListModel detects the change. The AppListView can thus use a transition animation when adding the entry. It is not required to fully redraw the list and exising items in the view are not affected.
import Felgo import QtQuick App { AppPage { id: page // property with json data property var jsonData: [ { "id": 1, "title": "Entry 1" }, { "id": 2, "title": "Entry 2" }, { "id": 3, "title": "Entry 3" } ] // list model for json data JsonListModel { id: jsonModel source: page.jsonData keyField: "id" } // list view AppListView { anchors.fill: parent model: jsonModel delegate: SimpleRow { text: model.title } // transition animation for adding items add: Transition { NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 1000 easing.type: Easing.OutQuad; } } } // Button to add a new entry AppButton { anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom text: "Add Entry" onClicked: { var newItem = { "id": jsonModel.count + 1, "title": "Entry "+(jsonModel.count + 1) } page.jsonData.push(newItem) // manually emit signal that jsonData property changed // JsonListModel thus synchronizes the list with the new jsonData page.jsonDataChanged() } } } // Page }
To learn about ListView features in general, you can find more examples here: Use ScrollViews and ListViews in Your App.
As the JsonListModel is a regular QML ListModel, it is compatible with SortFilterProxyModel and also supports list sections:
import Felgo import QtQuick App { AppPage { id: page // property with json data property var jsonData: [ { "id": 1, "title": "Apple", "type": "Fruit" }, { "id": 2, "title": "Ham", "type": "Meat" }, { "id": 3, "title": "Bacon", "type": "Meat" }, { "id": 4, "title": "Banana", "type": "Fruit" } ] // list model for json data JsonListModel { id: jsonModel source: page.jsonData keyField: "id" fields: ["id", "title", "type"] } // SortFilterProxyModel for sorting or filtering lists SortFilterProxyModel { id: sortedModel // Note: when using JsonListModel, the sorters or filter might not be applied correctly when directly assigning sourceModel // use the Component.onCompleted handler instead to initialize SortFilterProxyModel Component.onCompleted: sourceModel = jsonModel sorters: LocaleAwareSorter { id: typeSorter; roleName: "type"; ascendingOrder: true } } // list view AppListView { anchors.fill: parent model: sortedModel delegate: SimpleRow { text: model.title } section.property: "type" section.delegate: SimpleSection { } } // Button change the sorting order AppButton { anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom text: "Change Order" onClicked: typeSorter.ascendingOrder = !typeSorter.ascendingOrder } } // Page }
To correctly have relevant model roles available for SortFilterProxyModel, make sure to specify all required JsonListModel::fields.
count : int |
Returns the number of list items.
fields : array |
Defines the available fields of the model. If not set, the JsonListModel will use the first appended record as reference. You are not able to change the available fields once the model holds data using the given fields.
Example:
JsonListModel { keyField: "id" fields: [ "id", "value" ] }
keyField : string |
Sets the key field of the data source. The value in key field should be unique for each entry of the list.
If the key field is not set, JsonListModel won't be able to identify insertion, removal and moving of items.
source : array |
JsonListModel is a wrapper for Javascript arrays. Updates to the source
property will trigger synchronization of JsonListModel.
The list model then emits changes according to the difference of the current and new data set.
Example:
JsonListModel { keyField: "id" source: [ { "id": "a", "value": 1 }, { "id": "b", "value": 2 } ] fields: [ "id", "value" ] }
void append(var value) |
Appends value as new item at the end of the list.
Gets the index of a record that matches the input value for a given field.
If no matching record is found, the function returns -1.
Deletes the content at index from the model. You can specify the number of items to be removed with the count argument.
Changes multiple properties for the list entry at the given index position. Properties that are not part of the changes object are left unchanged.
A new item is appended to the list if the index
is equal to count. Otherwise, index
must match an element in the list.
Assigns the passed value to a given property of the list item positioned at index. Only the specified property will be set for the item.
|
When the source property changes, the JsonListModel automatically synchronizes to match the new JSON data. Adapting the source JSON data is thus the preferred way for making changes to the model.
Changes done with ListModel methods like append(), insert(), set(), setProperty(), move() or remove() only exist temporary until the next synchronization happens.
If you want to use these methods to make temporary changes, you can call the JsonListModel::syncModelToSource() method to apply your changes back into JsonListModel::source.
This method was introduced in Felgo 4.0.0.