5. Adding support for AdvancedCriteria with Ruby on Rails

Description

In this example the last sample will be modified to make use of the FilterBuilder and the underlying AdvancedCriteria system, to build functionality resembling this showcase sample (but using our supplyItem DataSource, instead of the one in the webpage)

Adding FilterBuilder to front-end

Modify app/assets/javascripts/smartclient_ui.js to include the relevant code for creating the FilterBuilder:

smartclient_ui.js
isc.FilterBuilder.create({
    "ID": "advancedFilter",
    "dataSource": "supplyItem",
    "topOperator": "and"
});

The ListGrid also requires additional code to add the FilterBuilder. This will require adding a vertical layout (VStack), together with the grid and the button needed to add for applying the filter on the ListGrid. Also going to add a horizontal layout (HStack) which will contain the two already existing buttons used for saving all data and creating a new record:

smartclient_ui.js
isc.ListGrid.create({
    ID: "supplyItemGrid",
    width: 700, height: 224, alternateRecordStyles: true,
    dataSource: supplyItem,
    autoFetchData:true,
    dataPageSize:20,
    canEdit:true,
    canRemoveRecords:true,
    autoSaveEdits: false
});
isc.IButton.create({
    ID: "filterButton",
    title: "Filter",
    click: function () {
        supplyItemGrid.filterData(advancedFilter.getCriteria());
    }
});
isc.HStack.create({
    membersMargin: 10,
    ID: "gridButtons",
    members: [
        isc.DynamicForm.create({
            values: { dataSource: "Change DataSource" },
            items: [
                { name: "dataSource", showTitle: false, editorType: "select",
                    valueMap: ["supplyItem", "employee"],
                    change: function (form, item, value, oldValue) {
                        if (!this.valueMap.contains(value)) return false;
                        else {
                            supplyItemGrid.setDataSource(value);
                            advancedFilter.setDataSource(value);
                            supplyItemGrid.filterData(advancedFilter.getCriteria());
                        }
                    }
                }
            ]
        }),
        isc.IButton.create({
            top: 250,
            title: "Edit New",
            click: "supplyItemGrid.startEditingNew()"
        }),
        isc.IButton.create({
            top: 250,
            left: 100,
            title: "Save all",
            click: "supplyItemGrid.saveAllEdits()"
        }),
    ]
});
isc.VStack.create({
    membersMargin: 10,
    members: [advancedFilter, filterButton, supplyItemGrid, gridButtons]
});

Also note, the filter has been removed top of the grid, as it is being replaced with the FilterBuilder.

Parsing the AdvancedCriteria

The smartclient gem can parse the advanced criteria, if you take a look at the source code of the smartclient gem, you will find the fetch method in the DataSource.rb in the gem library direcotry, after you bundled the smartclient gem.

The AdvancedCriteria built by the FilterBuilder is sent in the JSON payload when doing a fetch() request. It is formatted like this:

AdvancedCriteria JSON Foramat
// an AdvancedCriteria
{
    "_constructor":"AdvancedCriteria",
    "operator":"and",
    "criteria":[
        // this is a Criterion
        { "fieldName":"salary", "operator":"lessThan", "value":"80000" },
        { "fieldName":"salary", "operator":"lessThan", "value":"80000" },
            ...  possibly more criterions ..
        { "operator":"or", "criteria":[
            { "fieldName":"title", "operator":"iContains", "value":"Manager" },
            { "fieldName":"reports", "operator":"notNull" }
            { "operator":"and", "criteria": [
                .. some more criteria or criterion here
            ]}
        ]}
        },
        { "operator":"or", "criteria":[
            { "fieldName":"title", "operator":"iContains", "value":"Manager" },
            { "fieldName":"reports", "operator":"notNull" }
        ]}
            .. possibly more criterions or criterias
    ]
}

As you can see it is a tree structure, with it's leafs being criterion and the nodes being criteria. If the the criteria member is null, then it is a leaf, otherwise it is a node which has sub-criterias or sub-criterions.