Version 11.6 of Mi-Apps introduced a new set of data replication APIs. These APIs are designed to help app designers more easily check the status of data resources the app requires as well as perform complex conditional queries that aren't handled by Frictionless Data Replication


In order to use these APIs, an app must first be subscribed to a data resource. 


A data resource can be configured directly from the Mi-Enterprise Middleware Server. In this case, a data resource named "Automobiles" was created from a single CSV file named "cars.csv" as shown below:



Once this resource is created, a form must be subscribed to it. The screenshot below shows a form in the NextGen designer subscribed to the resource:



Note that while the form has drop down fields for Make and Model, unlike in the Frictionless Data Replication example, no fields are actually bound to columns within the data resource at this stage of form design. Even without that binding, Mi-Apps will automatically register the app for the required data. The user that is using the form within Mi-Apps must have Data Replication Reader permissions and must be allowed permissions to the data resource.


Once the steps above have been completed, the form may then make use of the Data Replication APIs. Let's first look at a way to query how recently the data resource has been modified and synchronized. This code can be added to the form's AfterOpen event:


// Triggered when the form is opened
function EH_AfterOpen() {
_form.dataResource("Automobiles")
    .then(function(resource) {
        _form.setValue("LastSyncDate", resource.lastSyncDate.toString());
        _form.setValue("LastModifiedDate", resource.lastModifiedDate.toString());
    })
    PopulateMakes();
}


The first portion of this API: _form.dataResource("Automobiles") tells the form to access the data resource with the name "Automobiles". Since this call is asynchronous, we need to tell the form what to do once the resource is opened. The code example above uses the JavaScript Promises syntax to take an action. In this case two other fields in the form are set to the dates the resource was last synced and last modified. The last sync date corresponds to the date and time on which the data resource was synchronized to the local device. The last modified date corresponds to the date and time the resource was modified at the server. It is typical for the sync date to be more recent than the modified date.


Let's take a look at another common task, populating a drop down list with items from the database. The code sample below is from the PopulateMakes() function. It queries unique makes of cars from the cars table (CSV file) within the data resource:


function PopulateMakes()
{
    _form.queryDataResource("Automobiles", "select distinct Make from cars order by Make", [])
        .then(function (rows)
        {
            var tuples = [];
            for (var i=0; i<rows.length; i++) {
                tuples.push([rows[i].Make]);
            }
            _form.picklistValueTuples("Make", tuples);
        });
}


The _form.queryDataResource allows form script to run a SQL query against the data resource. Once again a JavaScript Promise syntax is used to handle the asynchronous call. This API will return an array of objects each of which has a property per column within the entity from which it was queried. In this case we only care about the Make column and thus create an array with which to populate the value tuples of the Make field.


We can perform a similar type of query when the Make field is changed. In this case when the user selects a make we want to populate all models that correspond to that make. This can be done by handling the AfterSetData event as follows:


// Triggered when a field's value changes
function EH_AfterSetData(fieldName) {
    if (fieldName == "Make")
    {
        _form.queryDataResource("Automobiles", "select Model from cars where Make=? order by Model", [_form.getValue("Make")])
        .then(function (rows)
        {
            _form.setValue("Model", "");
            var tuples = [];
            for (var i=0; i<rows.length; i++) {
                tuples.push([rows[i].Model]);
            }
            _form.picklistValueTuples("Model", tuples);
        }); 
    }
}


Note that this example uses a parameter to the SQL query. The second argument to the _form.queryDataResource() function is expected to be an array of parameter values. In this case only the Make is required. The handling of the promise in this case populates the Model field options.


You may also use the APIs to force a synchronization of the data resource. The code below shows a sync and then updates the other fields on the form when a hotspot is pressed:


// Triggered when a hotspot is pressed
function EH_HotspotPressed(fieldName) {
    _form.dataResource("Automobiles")
        .then(function(resource) {
            resource.sync()
            .then(function(result) {
                if (!result.statusIsError()) 
                {
                    _form.setValue("LastSyncDate", resource.lastSyncDate.toString());
                    _form.setValue("LastModifiedDate", resource.lastModifiedDate.toString());
                    PopulateMakes();
                }
                else {
                    _form.showAlert("Syncing failed: " + result.status.toString() + " -- " + result.details);
                }
            })
            .catch(function(err) {
                if (err instanceof MEADataPlugin.MEADataResponse) {
                    _form.showAlert('Sync error: ' + MEADataPlugin.ResponseStatusNames[err.status]);
                } else {
                    _form.showAlert('Unexpected error: ' + JSON.stringify(err));
                }            
            })
        })
}


Note here that there are two chained promises as accessing the data resource is asynchronous and the sync is also asynchronous. 


An example form is attached for reference.