Today I’m going to explain how to Sort, Filter and Group data within a List (sap.m.List) or a  table (sap.m.Table) with the ViewSettingsDialog element in a dynamic form.

Filtering%20data%20of%20the%20example

Filtering data of the example

Context

The columns and their values to be used to sort, filter and group can be defined statically in the XML view of the ViewSettingsDialog (see an SAP sample here).

In this case, the table can contain any type of values for a specific column, so the values cannot be defined statically. So, we have to develop a dynamic way to define the columns and their values.

Git repository of this blog application can be downloaded here.

Resolution

 1.  JSON

The dataset used for this example has the following structure:

{
    "d": {
        "results": [
            {
                "SupplierID": 1,
                "CompanyName": "New Orleans Cajun Delights",
                "CompanyType": "Sales",
                "Country": "USA"
            },
            {
                "SupplierID": 2,
                "CompanyName": "Exotic Liquids",
                "CompanyType": "Accounting",
                "Country": "UK"
            },]
    }
}

 

2. XML

2.1. MainView.view.xml

Define the table in the XML of the view where will be. This is the key step of the solution.

The columns of the Table/List must have their ID attribute with the same name as the corresponding JSON field they will show.

For example, the first column is ‘Supplier ID’ and will show the property ‘SupplierId’ of every supplier of the JSON, so it must have the attribute id=’SupplierId’ in the column definition:

<Table id="supplierTable" items="{suppliersModel>/d/results}" width="auto" class="sapUiResponsiveMargin">
	<infoToolbar>
		<OverflowToolbar id="suppliersFilterBar" design="Solid"  visible="false">
			<Text id="suppliersFilterLabel" />
		</OverflowToolbar>
	</infoToolbar>
	<headerToolbar>
		<OverflowToolbar>
			<ToolbarSpacer />
			<OverflowToolbarButton text="Sort" type="Transparent" icon="sap-icon://sort" iconFirst="true" width="auto" enabled="true" visible="true" iconDensityAware="false" press="handleOpenDialogSort" />
			<OverflowToolbarButton text="Filter" type="Transparent" icon="sap-icon://filter" iconFirst="true" width="auto" enabled="true" visible="true" iconDensityAware="false" press="handleOpenDialogFilter" />
			<OverflowToolbarButton text="Group" type="Transparent" icon="sap-icon://group-2" iconFirst="true" width="auto" enabled="true" visible="true" iconDensityAware="false" press="handleOpenDialogGroup" />
		</OverflowToolbar>
	</headerToolbar>
	<columns>
		<Column id="SupplierID" width="auto" hAlign="Left" vAlign="Top" minScreenWidth="Phone" demandPopin="true" popinDisplay="Inline" mergeDuplicates="false">
			<Text text="Supplier ID" width="auto" maxLines="1" wrapping="false" textAlign="Begin" textDirection="Inherit" visible="true" />
		</Column>
		<Column id="CompanyName" width="170px" hAlign="Left" vAlign="Top" minScreenWidth="Tablet" demandPopin="true" popinDisplay="WithoutHeader" mergeDuplicates="false">
			<Text text="Company name" width="auto" maxLines="1" wrapping="false" textAlign="Begin" textDirection="Inherit" visible="true" />
		</Column>
		<Column id="CompanyType" width="auto" hAlign="Left" vAlign="Top" minScreenWidth="Tablet" demandPopin="true" popinDisplay="Block" mergeDuplicates="false">
			<Text text="Company type" width="auto" maxLines="1" wrapping="false" textAlign="Begin" textDirection="Inherit" visible="true" />
		</Column>
		<Column id="Country" width="auto" hAlign="Right" vAlign="Top" minScreenWidth="Phone" demandPopin="true" popinDisplay="Inline" mergeDuplicates="false">
			<Text text="Country" width="auto" maxLines="2" wrapping="true" textAlign="Begin" textDirection="Inherit" visible="true" />
		</Column>
	</columns>
	<items>
		<ColumnListItem type="Navigation">
			<ObjectAttribute text="{suppliersModel>SupplierID}" visible="true"/>
			<ObjectAttribute text="{suppliersModel>CompanyName}" textDirection="Inherit" visible="true" />
			<ObjectAttribute text="{suppliersModel>CompanyType}" textDirection="Inherit" visible="true" />
			<ObjectAttribute text="{suppliersModel>Country}" />
		</ColumnListItem>
	</items>
</Table> 

2.2. MainFilter.fragment.xml

Create a new fragment called ‘MainFilter’ to use it as a container to show the Sorting, Filtering and Grouping options to the user in a new Dialog. Add the following code:

<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core">
    <ViewSettingsDialog confirm="handleConfirm">
        <sortItems />
        <groupItems />
        <filterItems />
    </ViewSettingsDialog>
</core:FragmentDefinition>

 

3. MainView.controller.js

This controller will manage the MainView view and also the MainFilter fragment. If desired and for better clean code approach, the following code can also be inserted in a separated controller for the MainFilter fragment.

3.1. Define toolbar buttons handlers.

As defined in the MainView, the buttons for Filtering, Sorting and Grouping are defined inside the table toolbar. Every button has a handler method to be called when is pressed, and will open the corresponding section of the ViewSettingsDialog (Filter, Sort or Group).

Define the handlers:

// Opens View Settings Dialog on Filter page
handleOpenDialogSort: function() {
  this._openDialog("MainFilter", "sort", this._presetSettingsItems);
},
// Opens View Settings Dialog on Filter page
handleOpenDialogFilter: function() {
  this._openDialog("MainFilter", "filter", this._presetSettingsItems);
},
// Opens View Settings Dialog on Filter page
handleOpenDialogGroup: function() {
  this._openDialog("MainFilter", "group", this._presetSettingsItems);
}

3.2. Define ‘_openDialog’ method.

This method opens the ViewSettingsDialog. It has the common code structure that SAP shows in the samples for opening any type of Dialog:

_openDialog: function(sName, sPage, fInit) {
    let oView = this.getView(),
        oThis = this;

    // creates requested dialog if not yet created
    if (!this._mDialogs[sName]) {
        this._mDialogs[sName] = Fragment.load({
            id: oView.getId(),
            name: "com.sap.build.standard.findingactions.view." + sName,
            controller: this
        }).then(function(oDialog) {
            oView.addDependent(oDialog);
            if (fInit) {
                fInit(oDialog, oThis);
            }
            return oDialog;
        });
    }
    this._mDialogs[sName].then(function(oDialog) {
        oDialog.open(sPage); // opens the requested dialog page
    });
}

3.3. Define ‘_presetSettingsItems’.

Short method that wraps three other methods calls: one for Filtering, one for Sorting and the last one for Grouping:

_presetSettingsItems: function(oDialog, oThis) {
    oThis._presetFiltersInit(oDialog, oThis);
    oThis._presetSortsInit(oDialog, oThis);
    oThis._presetGroupsInit(oDialog, oThis);
}

3.4. Define ‘_presetFiltersInit’.

This method set the content of ‘Filter’ page of ViewSettingsDialog:

_presetFiltersInit: function(oDialog, oThis) {
    let oDialogParent = oDialog.getParent(),
        oModelData = oDialogParent.getController().getOwnerComponent().getModel("suppliersModel").getData(),
        oTable = oDialogParent.byId("supplierTable"),
        oColumns = oTable.getColumns();
    // Loop every column of the table
    oColumns.forEach(column => {
        let columnId = column.getId().split("--")[2], // Get column ID (JSON Property)
            oColumnItems = oModelData.d.results.map(oItem => oItem[columnId]), // Use column ID as JSON property (Here's the magic !)
            oUniqueItems = oColumnItems.filter((value, index, array) => array.indexOf(value) === index), // Get all unique values for this column
            oUniqueFilterItems = oUniqueItems.map(oItem => new ViewSettingsItem({ // Convert unique values into ViewSettingsItem objects.
                text: oItem,
                key: columnId + "___" + "EQ___" + oItem // JSON property = Unique value
            }));
        // Set this values as selectable on the filter list
        oDialog.addFilterItem(new ViewSettingsFilterItem({
            key: columnId, // ID of the column && JSON property
            text: column.getAggregation("header").getProperty("text"), // Filter Name -> Column Text
            items: oUniqueFilterItems // Set of possible values of the filter
        }));
    })
}

3.5. Define ‘_presetSortsInit’ ‘.

This method set the content of ‘Sort’ page of ViewSettingsDialog:

_presetSortsInit: function(oDialog, oThis) {
    let oDialogParent = oDialog.getParent(),
        oTable = oDialogParent.byId("supplierTable"),
        oColumns = oTable.getColumns();
    // Loop every column of the table
    oColumns.forEach(column => {
        let columnId = column.getId().split("--")[2]; // Get column ID (JSON Property)
        oDialog.addSortItem(new ViewSettingsItem({ // Convert column ID into ViewSettingsItem objects.
            key: columnId, // Key -> JSON Property
            text: column.getAggregation("header").getProperty("text"),
        }));
    })
}

3.6. Define ‘_presetGroupsInit’ ‘.

This method set the content of ‘Group’ page of ViewSettingsDialog:

_presetGroupsInit: function(oDialog, oThis) {
    let oDialogParent = oDialog.getParent(),
        oTable = oDialogParent.byId("supplierTable"),
        oColumns = oTable.getColumns();

    this.mGroupFunctions = {};
    // Loop every column of the table
    oColumns.forEach(column => {
        let columnId = column.getId().split("--")[2]; // Get column ID (JSON Property)
        oDialog.addGroupItem(new ViewSettingsItem({ // Convert column ID into ViewSettingsItem objects.
            key: columnId, // ID of the column && JSON property
            text: column.getAggregation("header").getProperty("text") // Filter Name -> Column Text
        }));
        // Set group functions
        let groupFn = function(oContext) {
            var name = oContext.getProperty(columnId);
            return {
                key: name, // ID of the column && JSON property
                text: name // Filter Name -> Column Text
            };
        }
        this.mGroupFunctions[columnId] = {};
        this.mGroupFunctions[columnId] = groupFn;
    });
}

3.7. Define ‘handleConfirm’.

This method is called when the user applies some Filtering/Sorting/Grouping by clicking the ‘OK’ button of the ViewSettingsDialog.

handleConfirm: function(oEvent) {
    let oTable = this.byId("supplierTable"),
        mParams = oEvent.getParameters(),
        oBinding = oTable.getBinding("items"),
        aFilters = [],
        sPath,
        bDescending,
        aSorters = [],
        vGroup,
        aGroups = [];

    // Filtering
    if (mParams.filterItems) {
        mParams.filterItems.forEach(function(oItem) {
            let aSplit = oItem.getKey().split("___"),
                sPath = aSplit[0],
                sOperator = aSplit[1],
                sValue1 = aSplit[2],
                sValue2 = aSplit[3],
                oFilter = new Filter(sPath, sOperator, sValue1, sValue2);
            aFilters.push(oFilter);
        });
        // apply filter settings
        oBinding.filter(aFilters);
        // update filter bar
        this.byId("suppliersFilterBar").setVisible(aFilters.length > 0);
        this.byId("suppliersFilterLabel").setText(mParams.filterString);
    }
    // Sorting
    if (mParams.sortItem) {
        sPath = mParams.sortItem.getKey();
        bDescending = mParams.sortDescending;
        aSorters.push(new Sorter(sPath, bDescending));
        // apply the selected sort and group settings
        oBinding.sort(aSorters);
    }
    // Grouping
    if (mParams.groupItem) {
        sPath = mParams.groupItem.getKey();
        bDescending = mParams.groupDescending;
        vGroup = this.mGroupFunctions[sPath];
        aGroups.push(new Sorter(sPath, bDescending, vGroup));
        // apply the selected group settings
        oBinding.sort(aGroups);
    } else if (this.groupReset) {
        oBinding.sort();
        this.groupReset = false;
    }
}

 

With all these code snippets the application would be finished. If you want to download the complete application of this blog and run it locally, access to my git repository here.

Regards,

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x