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: 
former_member185511
Active Participant

Facet filter is a very cool filter control which can be used in crowded tables. Unlike column filter in grid table, it allows multi selection.


You can check explored for more detail.


During the usage of facet filter, you might notice that after selecting values, the content is not dynamically populated based on the filtered rows. By default, there is no direct connection between facet filter content and the filtered table content.


Lets say user want to filter products and later on suppliers based on filtered products row. By default, user will select products from "Products" filter but when they come to "Suppliers" filter  still they will see all values which doesn't look proper.

There is a way of doing it before list open (haven't tried myself) but it is not capturing if you have both column filter(with sap.ui.table) and facet filter. Lodash method always populates based on the active table contents and i find this method much more easier.


What we are going to do is, we will implement Lodash library and pre-populate facet filter content dynamically based on table content. Lodash is javascript library which contains functions that makes it easier to work with arrays and I really cannot imagine my UI5 programming without it. Whenever you feel terrified, petrified, mortified, stupified or stressed and depressed, just open a code playground and fix some complex array scenarios with Lodash :). 


I am going to demonstrate it by using codepen which my another code playground tool. It allows you create folder structure and include third party libraries without any issue.


Content of facet filter data looks something like this;



Below is a the detail of attributes;


JSON content of the facet filter should be as below;




  • FACET_ID: Column name for the data coming from JSON and to be used during filtering.

  • FACET_TITLE : What users see before click.

  • VALUES : List to be populated after click.

    • FILTER_ID : Value to be used for filtering with FACET_ID

    • FILTER_DESC : Value shown to user




We are going to populate our facet filter after our rows are populated. For this purpose, we are going to use  attachChange event of the table binding after rendering.



   onAfterRendering: function() {
var bind = this.getView().byId("idProductsTable").getBinding("items");
bind.attachChange(this.RowBindingChange);
},

For filtering, sorting or after any row binding change, method “RowBindingChange” will be triggered. onAfterRendering will be triggered only once after page is rendered so please don’t confuse. What makes our function always to be triggered is “attachChange” event.


After each RowBindingChange event triggered, our algorithm will follow below steps;




  • Get existing filtered rows from table (not only visible! it is binded rows! ).

  • Decide what columns will be added to facet filter

  • Get unique records for each column to be filtered.

  • Prepare content and update model


 

Here is the flow of RowBindingChange

 
 RowBindingChange: function(oEvent) {

First we get the existing rendered rows.
       var that = this;
var data = [];
// get binded rows into data!
var oList = oEvent.getSource().oList;
$.each(oEvent.getSource().aIndices, function(a, b) {
data.push(oList[b]);
});

Now we need to configure which columns needs to appear in facet filter;
       // facet configuration
var filter_header = [];

//filter products. column name is Name in our JSON content for that array
//we will use FILTER_ID during filtering. Generally it is better to use ID here rather than description
var filter_product = {
COL: "Name",
FILTER_ID: "Name",
FILTER_NAME: "Name"
};
// add supplier as well
var filter_supplier = {
COL: "SupplierName",
FILTER_ID: "SupplierName",
FILTER_NAME: "SupplierName"
};
// facet header configuration. TITLE is what users will see on top. FACET_ID will be used during filtering and values will be shown to user.
var filter_product_header = {
FACET_TITLE: "Products",
FACET_ID: "Name",
VALUES: filter_product
};

var filter_supp_header = {
FACET_TITLE: "Suppliers",
FACET_ID: "SupplierName",
VALUES: filter_supplier
};
//populate config!
filter_header.push(filter_product_header);
filter_header.push(filter_supp_header);

Configuration for facet filter is done! Now we need to populate the content for facet filter. Here we are using map and uniqBy method.

Map function will trigger function for each item in the array and that array will be populated by uniqBy function based on the column and array we are passing.
      // FACET_BUILD for title and values
function FACET_BUILD(IV_FACET_TITLE, IV_FACET_ID, IT_VALUES) {
var result = {
FACET_TITLE: IV_FACET_TITLE,
FACET_ID: IV_FACET_ID,
VALUES: IT_VALUES
};
return result;
}
//We need to get unique rows with Lodash from the table rows [obj parameter].
//and return in proper structure.
function FACET_GET_VALUES(IV_COL, IV_FILTER_ID, IV_FILTER_NAME, obj) {
var result = _.map(_.uniqBy(obj, IV_COL), function(item) {
return {
FILTER_ID: item[IV_FILTER_ID],
FILTER_DESC: item[IV_FILTER_NAME]
};
});
return result;
}

Now we can use our config data and populate facet filter.
        var FACET_FILTER = [];
// prepare values for filter
_.each(filter_header, function(obj) {
var FACET_VAL = FACET_GET_VAL(
obj.VALUES.COL,
obj.VALUES.FILTER_ID,
obj.VALUES.FILTER_NAME,
data
);
//populate final data!
var FACET_HEADER = FACET_GET_HEADER(
obj.FACET_TITLE,
obj.FACET_ID,
FACET_VAL
);
//collect
FACET_FILTER.push(FACET_HEADER);
});
// finally update model!. It is better not to use global models but this is for test purpose.
sap.ui.getCore().getModel().setProperty("/FACET_FILTER", FACET_FILTER);

console.log(FACET_FILTER);

After binding filter events of facet filter, application should be ready. I am not going to explain filtering events, you can find it at the bottom of the page. I included reset button as well to roll back filtering and all.

 

 

Here you can find the full application.

https://codepen.io/bilencekic/project/editor/ZMWNmJ

Have a nice day!

Keep your enemies close and javascript libraries closer.

 
2 Comments
Labels in this area