Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
sergiorecasens
Participant
Dear SAP Users,

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 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,

 

Sergio.
Labels in this area