DataModel Change Trigger

As I am working through creating a minimum application template, I want to make sure I have the features that will be needed in almost any application.  One of those would be to trigger a notification that the DataModel has been updated.  An example use of this is a ListView populated using a DataModel.  In the application I created for work, when I add a new sales lead through the form, the user gets sent back to a ListView of all the entered leads saved in the device sql database.  After the data is inserted into the table successfully, then the dataModelChanged trigger which “refreshes” the datamodel.  When the datamodel is “refreshes”, then the ListView that is built off of the datamodel “refreshes” and you see the new or updated record.   While this wasn’t obvious on the application during a save, it was obvious when the lead was sent to the web service, because I had the ListItemComponent status value change from the lead id to “Saved”.  That takes another little trick using a javascript function, which I will post about later.

The setup for the datamodel trigger is fairly straight forward.  First, you need to add the datamodel to the class as a property and as an accessible parameter.  In my application, since the applicationui was the main class, the datamodel was added there.  You also need to have a parameter to call the the data in the model attached to the class.

In the class header (applicationui.hpp).


class ApplicationUI : public QObject
{
Q_OBJECT

// A property that is used by the list view in QML
Q_PROPERTY(bb::cascades::DataModel* dataModel READ dataModel NOTIFY dataModelChanged CONSTANT)

public:
  ApplicationUI(bb::cascades::Application *app);
  ApplicationUI();
  virtual ~ApplicationUI() { }

  Q_SIGNALS:
    void dataModelChanged();
  public Q_SLOTS:
  private Q_SLOTS:
  private slots:
  private:
    // The getter method for the property
    bb::cascades::GroupDataModel* dataModel() const;
    // The data shown by the list view.
    bb::cascades::GroupDataModel* m_dataModel;
};

Then you need to make sure you initiate the data model.  In the example below, the “leadID” is being used to sort the data model group.  When you do an create or update call, you need to trigger that the data model has changed by simply call “emit dataModelChanged()”, which was set in the class head property.  And, most importantly, you need to read in the data to the data model, so that there is something to see.  In this example, there is a class called Person that holds each lead record, which is then added to the data model.

In the class source (applicationui.cpp)


ApplicationUI::ApplicationUI(bb::cascades::Application *app) :
QObject(app),
m_dataModel(0), m_lastLeadID(0), m_succeeded(false), m_active(false)
{
  initDataModel();
  // Initialize the database, ensure a connection can be established  and that all the required tables and initial data exists
  const bool dbInited = initDatabase();
  if(dbInited) {
    readLeadRecords();
  }
}
void ApplicationUI::initDataModel()
{
  // Note: The Group Data Model is joining this objects tree as a child (for memory management)
  m_dataModel = new GroupDataModel(this);
  m_dataModel->setSortingKeys(QStringList() << "leadID");
  m_dataModel->setSortedAscending(false);
  m_dataModel->setGrouping(ItemGrouping::None);
}
bool ApplicationUI::createLeadRecord(const QString &firstName,...)
{
  .... do sql insert
  emit dataModelChanged();
  return success;
}

bool ApplicationUI::updateLeadRecord(const QString &firstName,...)
{
  .... do sql update
  emit dataModelChanged();
  return success;
}
void ApplicationUI::readLeadRecords()
{
  .... do sql select
  // The data will be displayed in a group data model
  // Clear any previous reads from the data model first
  m_dataModel->clear();
  while (query.next()) {
    // create person object for insert into group data model
    Person *person = new Person(query.value(0).toString, ....);
    // insert into group data model
    m_dataModel->insert(person);
  }
}

Finally, you can setup the ListView in a Page Container and point the dataModel to the one referenced in the main class header.


import bb.cascades 1.2
//! [0]
Page {

  Container {
    bottomPadding: 30

    ListView {
      id: leadsList
      horizontalAlignment: HorizontalAlignment.Fill
      dataModel: _app.dataModel
    }
  }
}

The issue I had with my application was that I had a separate class for the web service calls.  On the web service result, I wanted to update the database to set a field “savedToServer” to 1 (true).  I had no problem doing that, but I couldn’t call the data model updated call from that class.  In the end, I moved my web services calls to the main class, but that’s not how I want things to work.  So, hopefully, with my minimum template setup, I can call things between classes without any issue.

About DeanLogic
Dean has been playing around with programming ever since his family got an IBM PC back in the early 80's. Things have changed since BASICA and Dean has dabbled in HTML, JavaScript, Action Script, Flex, Flash, PHP, C#, C++, J2ME and SQL. On this site Dean likes to share his adventures in coding. And since programming isn't enough of a time killer, Dean has also picked up the hobby of short film creation.

About DeanLogic

Dean has been playing around with programming ever since his family got an IBM PC back in the early 80's. Things have changed since BASICA and Dean has dabbled in HTML, JavaScript, Action Script, Flex, Flash, PHP, C#, C++, J2ME and SQL. On this site Dean likes to share his adventures in coding. And since programming isn't enough of a time killer, Dean has also picked up the hobby of short film creation.