Files:
The Paged DataModel example demonstrates how to implement a custom DataModel that reloads data on demand.
In this example we'll learn how to implement a custom DataModel that shows a list of numbers from 0 to 19 plus an additional item 'Click for more...'. If the user selects this special item, the model is extended by 10 additional items.
The UI of this sample application consists of a ListView that simply shows the content of our custom model and a Label at the top that shows the number of currently loaded items.
We create the model in C++ and export it to QML, under the name '_model', as context property inside the main.cpp function.
QmlDocument* qml = QmlDocument::create("asset:///main.qml").parent(&app); qml->setContextProperty("_model", new PagedDataModel(&app));
Inside the main QML document, we simply bind this exported property against the 'dataModel' property of the ListView.
ListView { dataModel: _model ... onTriggered: { clearSelection() select(indexPath) if (indexPath[0] == (dataModel.childCount([]) - 1)) { // Last item selected _model.addItemsAt(indexPath); } }
Whenever the user clicks on an item, we update the selection and check whether the last item (the 'Click for more...') has been selected. In this case we invoke the addItemsAdd() slot on the PagedDataModel object.
The model furthermore provides a custom property 'itemCount' which we use to assemble the text of the header label.
Label { horizontalAlignment: HorizontalAlignment.Center text: qsTr("Number of items: %1").arg(_model.itemCount) textStyle { base: SystemDefaults.TextStyles.BigText color: Color.White } }
In this example we don't want to implement the model from scratch, so we inherit from QVariantListDataModel and just extend it by the needed functinality. We declare the custom 'itemCount' property with getter method and change notification signal and the addItemsAt() method.
class PagedDataModel : public bb::cascades::QVariantListDataModel { Q_OBJECT Q_PROPERTY(int itemCount READ itemCount NOTIFY itemCountChanged) public: PagedDataModel(QObject *parent = 0); Q_INVOKABLE void addItemsAt(const QVariantList &indexPath); Q_SIGNALS: void itemCountChanged(); private: int itemCount() const; };
Inside the constructor we fill the model with the initial entries from 0 to 19 plus the additional marker item.
PagedDataModel::PagedDataModel(QObject *parent) { // Workaround since QVariantListDataModel is missing the parent parameter in constructor setParent(parent); // Fill the model initially with values '0' to '19' for (int row = 0; row < 20; ++row) { append(QString::number(row)); } // Add the marker item to request more items append(tr("Click for more...")); }
Inside the addItemsAt() method we extract the position of the clicked item from the indexPath and remove that item from the model (since we know it has been the marker). Afterwards we append 10 new items to the end of the model and re-add the marker item.
At the end we emit the change notification signal for our custom 'itemCount' property.
void PagedDataModel::addItemsAt(const QVariantList &indexPath) { // Check whether the index path is valid if (indexPath.size() != 1) return; // Retrieve position of marker in list const int position = indexPath[0].toInt(); // Remove the marker removeAt(position); // Append the new items for (int row = position; row < (position + 10); ++row) { append(QString::number(row)); } // Add a new marker item to request more items append(tr("Click for more...")); emit itemCountChanged(); }
The getter method of the 'itemCount' property simply returns the number of items in the model minus the one marker item.
int PagedDataModel::itemCount() const { return (size() - 1); }