Skip to Content
Technical Articles

SAPUI5 FilterBar with SmartVariantManagement

Objective

Create a custom FilterBar extension with a fully working SmartVariantManagement.

It requires minimal effort with the filters data, the rest is already implemented!

Backstory

I had a business requirement to create a custom Fiori app that should have a filter bar with variant management similar to the one from standard SAP applications.

The basic variant management for the FilterBar element (SmartVariantManagementUi2) lacks a lot of features (sharing, transport, apply automatically).

I tried using SmartFilterBar because it already has everything you need in terms of variant management. However, I stumbled upon some problems and also I did not know how to implement certain features so I decided to abandon it.

Then I have found this great blog that talks about creating a custom variant management using sap.ui.comp.variants.VariantManagement.

https://blogs.sap.com/2017/01/12/variant-management-implementation-using-shell-personalization-service/

I have also implemented all the features that the blog did not talk about. However, there are two problems, one is that the element is not IN the filter bar without maybe some workarounds, second is that the sharing (transporting) feature would be implemented manually which is not a comfortable thing to do.

Then this tutorial appeared in my searches. It talks about how to use SmartVariantManagement in the FilterBar. Unfortunately, it was not that straightforward as it says and this is what I will try to cover in this blog.

https://help.sap.com/doc/saphelp_uiaddon10/1.17/en-US/2a/e520a67c44495ab5dbc69668c47a7f/frameset.htm

Implementation

The SAPUI5 version I have worked on is 1.60.

Extend the FilterBar control

There are some modifications of the code from the FilterBar documentation above.

  1. There is not such method as addControl, use setControl
    oPersInfo.setControl(this)​;
  2. Use this._oSmartVM because there is no variable called oSmartVM.
    this._oSmartVM.addPersonalizableControl(oPersInfo);

     

  3. Overwrite the mehod _isTINAFScenario. The original one checks only with this._isUi2Mode() which verifies that the variant management is an instance of SmartVariantManagementUi2. Add a case for SmartVariantManagement.

The FilterBar.js file

Use this the same way you would use the standard FilterBar by including the xml namespace for custom.control.

sap.ui.define([
    "sap/ui/comp/filterbar/FilterBar",
    "sap/ui/comp/smartvariants/PersonalizableInfo",
    "sap/ui/comp/smartvariants/SmartVariantManagement"
], function (FilterBar, PersonalizableInfo, SmartVariantManagement) {
   "use strict";
   
   var CustomFilterBar = FilterBar.extend("custom.control.FilterBar", {
       renderer: function(oRm, oControl) {
           FilterBar.getMetadata().getRenderer().render(oRm, oControl);
       }
   });
   
   /**
    * Initialise variant management control
    * @private
    */
    CustomFilterBar.prototype._initializeVariantManagement = function () {
        if (this._oSmartVM && this.getPersistencyKey()) {
            var oPersInfo = new PersonalizableInfo({
                type: "filterBar",
                keyName: "persistencyKey"
            });
            oPersInfo.setControl(this);

            if (this._oSmartVM._loadFlex) {
                this._oSmartVM._loadFlex().then(function () {
                    this._oSmartVM.addPersonalizableControl(oPersInfo);
                    FilterBar.prototype._initializeVariantManagement.apply(this, arguments);
                }.bind(this));
            } else {
                this._oSmartVM.addPersonalizableControl(oPersInfo);
                FilterBar.prototype._initializeVariantManagement.apply(this, arguments);
            }
        } else {
            this.fireInitialise();
        }
    };
   
   /**
    * Use SmartVariantManagement instead of SmartVariantManagementUi2
    * Activate the public and apply automatically options
    * 
    * @private
    * @returns {sap.ui.comp.smartvariants.SmartVariantManagement} The variant management control
    */
   CustomFilterBar.prototype._createVariantManagement = function () {
       this._oSmartVM = new SmartVariantManagement({
           showExecuteOnSelection: true,
           showShare: true
       });
       
       return this._oSmartVM;
   };
   
   /**
    * The original method accepts only SmartVariantManagementUi2
    * 
    * @private
    * @returns {boolean} Result
    */
   FilterBar.prototype._isTINAFScenario = function() {
       if (this._oVariantManagement) {
           if (!this._isUi2Mode() && !(this._oVariantManagement instanceof SmartVariantManagement)) {
               return true;
           }
       } else {

           /* eslint-disable no-lonely-if */
           // scenario: VH dialog: VM replaced with collective search control
           if (this._oCollectiveSearch && this.getAdvancedMode()) {
               return true;
           }
           /* eslint-enable no-lonely-if */
       }

       return false;
   };
   
   return CustomFilterBar;
});

Events

By going throught the FilterBar source code, I have found that the variant management is never initialised. For this, you have to fire the filter bar’s initialise event manually which also initialises the variant management. I think it is convenient to fire it in the onAfterRendering event of the controller of the view that has the filter bar.

this.getView().byId("filterBarId").fireInitialise();

Register the methods for fetching and applying data. I registered them after calling fireInitialise.

this.getView().byId("filterBarId").registerFetchData(this.onFetchData.bind(this));
this.getView().byId("filterBarId").registerApplyData(this.onApplyData.bind(this));

Write the registered methods

The onFetchData method should return a custom JSON with relevant data for filters.

onFetchData: function () { … }

The onApplyData method gets the above saved JSON as a parameter for the selected variant. Use this to fill the filters.

onApplyData: function (oVariantContent) { … }

These two methods are the only things you have to implement based on your filters.

The options Set As Default, Public (sharing with transports included), Apply Automatically, Add as Favorite, Delete, Rename should work out of the box.

Dirty State

Add this method for whenever the variant should be in modified state, for example in the change event of a DatePicker. In the modified state, an asterisk will appear near the title of the variant and the Save button gets enabled if it’s not the standard variant.

onFilterChange: function () {
    var oVariantManagement = this.getView().byId("filterBarId").getVariantManagement();
    
    if (oVariantManagement) {
        oVariantManagement.currentVariantSetModified(true);
    }
},

Conclusion

This control should make it easy to have a variant management in any freestyle Fiori app used in an SAP system.

I hope it helped you out!

11 Comments
You must be Logged on to comment or reply to a post.
  • A very helpfull blog. Big thanks Alex Necula !

     

    But there is one question left for me.

    Is the initialising wirtten in the "onAfterRendering" of the FilterBar.js or in the controller of the view, where i am using the FilterBar?

    This question refers also to "onFetchData"- and "onApplyData"-Function?

    • Hi Victor,

      Thank you for the appreciation!

      The below code is written in the onAfterRendering of the controller of the view where you are using the FilterBar.

      this.getView().byId("filterBarId").fireInitialise();
      this.getView().byId("filterBarId").registerFetchData(this.onFetchData.bind(this));
      this.getView().byId("filterBarId").registerApplyData(this.onApplyData.bind(this));

       

      onFetchData and onApplyData functions are also written in the same controller.

      Please let me know if there is something else I can help you with.

      Alex

      • Thanks for that quick response!

         

        Allright, so I implemented it the correct way but i am facing this problem... Did I miss anything from your blog?

        Does this occurs, because the onFetchData and onApplyData are not filled with logic?

        /
        • Victor,

          It is possible that this error occurs because some libraries are loaded differently in a newer version of SAPUI5. Please replace the method _initializeVariantManagement inside FilterBar.js with the following and let me know if this works so I can update the blog.

          CustomFilterBar.prototype._initializeVariantManagement = function () {
              if (this._oSmartVM && this.getPersistencyKey()) {
                  var oPersInfo = new PersonalizableInfo({
                      type: "filterBar",
                      keyName: "persistencyKey"
                  });
                  oPersInfo.setControl(this);
          
                  if (this._oSmartVM._loadFlex) {
                      this._oSmartVM._loadFlex().then(function () {
                          this._oSmartVM.addPersonalizableControl(oPersInfo);
                          FilterBar.prototype._initializeVariantManagement.apply(this, arguments);
                      }.bind(this));
                  } else {
                      this._oSmartVM.addPersonalizableControl(oPersInfo);
                      FilterBar.prototype._initializeVariantManagement.apply(this, arguments);
                  }
              } else {
                  this.fireInitialise();
              }
          };

          Thank you,

          Alex

          • Are you running from a local environment?

            If yes, you might need to modify the proxy path to allow the communication with the backend server for lrep.

            For visual code studio (and probably sap business aplication studio) you should have the backend path of the customMiddleware equal to '/sap' instead of '/sap/opu/odata'.

            For SAP Web IDE you should add the path '/sap/bc/lrep' to neo-app.json.

            If neither of this works, you should still be able to deploy to the SAP system and check there.

          • Alright Alex Necula , to get my knowledge right of understanding how variants a saved:

            Variants are saved through

            'sap/ui/comp/smartvariants/PersonalizableInfo'

            which is independent from the used Abap-database?

          • Variants are saved through the ICF path /sap/bc/lrep in the system database.

            sap/ui/comp/smartvariants/PersonalizableInfo is an SAPUI5 control used by the framework in the process of saving. In this case it is used to specify what type of variant is used which is filter bar and what attribute of the control should be used to create the id in the database table which is persistencyKey. persistencyKey is an already existing attribute that was created for the variant management use case.