Skip to Content

Variant Management implementation using Shell Personalization service

Variant management:

The standard fiori variant management control allows the user to save the variant, open the existing variant(read variant) ,update the existing variant and delete the variant. It also allows to set the default variant.

This post targets at the implementation of variant management using the shell personalization service.

We used variant management control in combination with filter bar.

To start with personalization service of shell, we need to create the personalization container and variant set specific to our application. We can also create a different variant set for the default variant. Personalization variant set contains variants of personalization data.

View:

View with Filter bar and variant management control is as below. Filter items to the filter bar are added dynamically in the controller

<variant:VariantManagement variantItems="{/Variants}" standardItemText="{/DefaultVariant}" select="onSelectVariant" 
	save="onSaveAsVariant" enabled="true" manage="onManageVariant" showExecuteOnSelection="false" showShare="false" id="variantManagement">
		<variant:variantItems>
			<variant:VariantItem text="{VariantName}" key="{VariantKey}" selectionKey= "{VariantKey}"/>
		</variant:variantItems>
	</variant:VariantManagement>
	<fb:FilterBar reset="onReset" search="OnPressOfApplyInFilterBar" showRestoreButton="false" showClearButton="true" filterBarExpanded="false" 
	id="filterBar" clear="filterBarClearBtnPress" />

 

Fetching the variants:

getAllVariants: function(fnCallBack) {
        var oPersonalizationVariantSet= {},
            aExistingVariants =[],
            aVariantKeysAndNames =[];
        //get the personalization service of shell
        this._oPersonalizationService = sap.ushell.Container.getService('Personalization');
        this._oPersonalizationContainer = this._oPersonalizationService.getPersonalizationContainer("MyVariantContainer");
        this._oPersonalizationContainer.fail(function() {
            // call back function in case of fail
            fnCallBack(aExistingVariants);
        });
        this._oPersonalizationContainer.done(function(oPersonalizationContainer) {
            // check if the current variant set exists, If not, add the new variant set to the container
            if (!(oPersonalizationContainer.containsVariantSet('MyApplicationVariants'))) {
                oPersonalizationContainer.addVariantSet('MyApplicationVariants');
            }
            // get the variant set
            oPersonalizationVariantSet = oPersonalizationContainer.getVariantSet('MyApplicationVariants');
            aVariantKeysAndNames = oPersonalizationVariantSet.getVariantNamesAndKeys();
            for(var key in aVariantKeysAndNames){
                if (aVariantKeysAndNames.hasOwnProperty(key)) {
                    var oVariantItemObject = {};
                    oVariantItemObject.VariantKey = aVariantKeysAndNames[key];
                    oVariantItemObject.VariantName = key;
                    aExistingVariants.push(oVariantItemObject);
                }
            }
            fnCallBack(aExistingVariants);
        }.bind(this));
    }

“MyVariantContainer” is the name of the personalization container I used and “MyApplicationVariants” is the name of the personalization variant set.

In the callback function, set the model to variant management control.

 		var oVariantMgmtControl = this.getView().byId("variantManagement"),
            // create a new model
            oVariantModel = new sap.ui.model.json.JSONModel();
        //get Variants from personalization set and set the model of variants list to variant managment control
        this.getAllVariants(function(aVariants){
            oVariantModel.oData.Variants = aVariants;
            oVariantMgmtControl.setModel(oVariantModel);           
            //enable save button
            oVariantMgmtControl.oVariantSave.onAfterRendering = function(){this.setEnabled(true);};
        }.bind(this));

Now the existing variants that are present in the variant set will be shown in variant management control.

Generally the save button in the variant management control is disabled. We enabled it by adding

oVariantMgmtControl.oVariantSave.onAfterRendering = function(){this.setEnabled(true);};

Saving the variants:

“onSaveAsVariant” event will be fired on click of “Save” or “Save As”.

In the mParameters of event , you see a parameter “overwrite” set to “true” when you click on “Save” i.e. it saves the filters to the selected variant. It is set to false, when you are creating a new variant by clicking on “Save As”.

Gather the filter data in the filter bar and now save the variant to the variant set.

onSaveAsVariant: function(oEvent) {
		//oSelectedFilterData is the json object with the data seleced in the filter bar
 		this.saveVariant(oEvent.mParameters.name, oSelectedFilterData, function() {
            //Do the required actions
        }.bind(this));
	}

	/**
	 * This method is to save the variant
	 * @param {String} sVariantName- Variant name
	 * @param {Object} oFilterData- Filter data object-> consolidated filters in JSON
	 * @param {Function} fnCallBack- the call back function with the array of variants
	 */
	saveVariant: function(sVariantName, oFilterData, fnCallBack) {
	    // save variants in personalization container
	    this._oPersonalizationContainer.fail(function() {
	        // call back function in case of fail
	        fnCallBack(false);
	    });
	    this._oPersonalizationContainer.done(function(oPersonalizationContainer) {
	        var oPersonalizationVariantSet ={},
	            oVariant = {},
	            sVariantKey = "";
	        // check if the current variant set exists, If not, add the new variant set to the container
	        if (!(oPersonalizationContainer.containsVariantSet("MyApplicationVariants"))) {
	            oPersonalizationContainer.addVariantSet('MyApplicationVariants');
	        }
	        // get the variant set
	        oPersonalizationVariantSet = oPersonalizationContainer.getVariantSet('MyApplicationVariants');
	        
	        //get if the variant exists or add new variant
	        sVariantKey = oPersonalizationVariantSet.getVariantKeyByName(sVariantName);
	        if (sVariantKey) {
	               oVariant = oPersonalizationVariantSet.getVariant(sVariantKey);
	        } else {
	               oVariant = oPersonalizationVariantSet.addVariant(sVariantName);
	        }
	        if (oFilterData) {
	            oVariant.setItemValue('Filter', JSON.stringify(oFilterData));
	        }
	        oPersonalizationContainer.save().fail(function() {
	           //call callback fn with false
	            fnCallBack(false);
	        }).done(function() {
	           //call call back with true
	            fnCallBack(true);
	        }.bind(this));
	    }.bind(this));
	},

 

Managing the variant:

 

Managing the variants includes updating the name of existing variant or deleting the variant or changing the default variant.

“onManageVariant” event will be fired when you click on “OK ” in manage popup.

The event parameters gives the array of deleted variants, array of updated variants, and the default variant.

 onManageVariant: function(oEvent) {
        var aDeletedVariants = oEvent.mParameters.deleted,
            aRenamedVariants = oEvent.mParameters.renamed,
            sNewDefaultVariantKey = oEvent.mParameters.def;
        if (aDeletedVariants.length>0) {
	        this.deleteVariants(aDeletedVariants, function(bDeleted) {
	        	// delete success if bDeleted is true
	        });
        }
        if(aRenamedVariants.length>0) {
            // get the variants from variant set and rename them in the personalization variant set and then save it.
        }
    }
    
    
    deleteVariants: function(aVariantKeys, fnCallback) {
        var oPersonalizationVariantSet ={};
        this._oPersonalizationContainer.fail(function() {
            //handle failure case
        });
        this._oPersonalizationContainer.done(function(oPersonalizationContainer) {
            if (!(oPersonalizationContainer.containsVariantSet("MyApplicationVariants"))) {
                oPersonalizationContainer.addVariantSet("MyApplicationVariants");
            }
            oPersonalizationVariantSet = oPersonalizationContainer.getVariantSet("MyApplicationVariants");
            for (var iCount=0; iCount<aVariantKeys.length; iCount++) {
                if (aVariantKeys[iCount]) {
                    oPersonalizationVariantSet.delVariant(aVariantKeys[iCount]);
                }
            }
            oPersonalizationContainer.save().fail(function() {
                //handle failure case
            	fnCallback(false);
            }).done(function() {
                fnCallback(true);
            }.bind(this));
        }.bind(this));
    }

To set the default variant, you can use a different variants set , I used a property to in the filter to differentiate normal and default variant.

Select Variant:

On clicking on any variant in the variant list, “onSelectVariant” will be fired. Get the variant key and fetch the data in the variant.

onSelectVariant: function(oEvent) {
        var sSelectedVariantKey = oEvent.mParameters.key;
        if (sSelectedVariantKey) {
        	 this.getVariantFromKey(sSelectedVariantKey, function(oSelectedVariant){
                //logic with the data in variant --oSelectedVariant
            }.bind(this));
        }
    }
    getVariantFromKey: function(sVariantKey, fnCallback) {
        this._oPersonalizationContainer.fail(function() {
            // call back function in case of fail
            if (fnCallback) {
                fnCallback('');
            }
        });
        this._oPersonalizationContainer.done(function(oPersonalizationContainer) {
            var oPersonalizationVariantSet ={};
            // check if the current variant set exists, If not, add the new variant set to the container
            if (!(oPersonalizationContainer.containsVariantSet(Materials.Constants.VARIANT_SET_KEY))) {
                oPersonalizationContainer.addVariantSet(Materials.Constants.VARIANT_SET_KEY);
            }
            // get the variant set
            oPersonalizationVariantSet = oPersonalizationContainer.getVariantSet(Materials.Constants.VARIANT_SET_KEY);
            fnCallback(oPersonalizationVariantSet.getVariant(sVariantKey));
        });
    }

**
Enjoy Learning!!!

Thanks..

28 Comments
You must be Logged on to comment or reply to a post.
  • Thank you for providing such a interesting topic…. and i have some doubts in the above code and usage of codes…

    1. “oSelectedFilterData” function is note found in the code.
    2. where to call this function “getAllVariants”,

    is it possible to do all the operation without sap,ushell.container???

    • Hi,

      1. oSelectedFilterData is the filter object(JSON object with filter data) that I am trying to save as a variant .  Sorry for not mentioning it.
      2. getAllVariants can be called when you need the list of variants. It fetches the list of variants and then you can bind to your control.

        Personalization container is shell service, If you do not have shell container, it will save the varaints in cache and they will be cleared when you clear the cache. So not preferable or useful when you do not have a shell .

      • Thank you… is it possible to do the same operation without using shell?? like changing the metadata and saving the same in variant?? or some other idea??

        As i’m using gateway to execute my program.. it throws error on this line

        showing that “UITable.controller.js:418 Uncaught TypeError: Cannot read property ‘Container’ of undefined”

        /
  • Hi Anjani,

    thanks for sharing the information. But how can I determine the filter values from the filter bar?

    How can I fill oSelectedFilterData????

    Would be nice if you could also share this information.

    Thanks and regards, Thomas

  • Hi Anjani,

    I am using table perso controller for saving the personalization on using shell service.

    can u please explain what need to be done while selecting records by calling method  ” selectVarianMethod” and changing the the table layout accordingly?

    onSelectVariant: function(oEvent) {
            var sSelectedVariantKey = oEvent.mParameters.key;
            if (sSelectedVariantKey) {
            	 this.getVariantFromKey(sSelectedVariantKey, function(oSelectedVariant){
                    //logic with the data in variant --oSelectedVariant
                }.bind(this));
            }
        }
        getVariantFromKey: function(sVariantKey, fnCallback) {
            this._oPersonalizationContainer.fail(function() {
                // call back function in case of fail
                if (fnCallback) {
                    fnCallback('');
                }
            });
            this._oPersonalizationContainer.done(function(oPersonalizationContainer) {
                var oPersonalizationVariantSet ={};
                // check if the current variant set exists, If not, add the new variant set to the container
                if (!(oPersonalizationContainer.containsVariantSet(Materials.Constants.VARIANT_SET_KEY))) {
                    oPersonalizationContainer.addVariantSet(Materials.Constants.VARIANT_SET_KEY);
                }
                // get the variant set
                oPersonalizationVariantSet = oPersonalizationContainer.getVariantSet(Materials.Constants.VARIANT_SET_KEY);
                fnCallback(oPersonalizationVariantSet.getVariant(sVariantKey));
            });
        }

     

    Regards

    Shadan

     

     

  • Hi Ajani,

    first thank you for sharing this valuable information with us. Is it possible to save the variants global enabling other users to see my variants? If yes could you provide an code snippet ?

     

    Best regards

     

    Vural

    • EDIT: It seems that this tutorial uses a deprecated version of personalization container API. getContainer() should be used instead of getPersonalizationContainer() as seen here:

      https://sapui5.hana.ondemand.com/sdk/#/api/sap.ushell.services.Personalization

      Using this, the Variant object now has the method setVariantName.

      Note that you have to get the VariantSet object a little different.

      Original post:

      I know it’s late but for the other people, you can use something like this.

      I am aware that modifying a private member is not recommended but I could not find another way.

      _renameVariants: function (aRenamedVariants) {
          this._oPersonalizationContainer.fail(function () {
              // Error handling
          }.bind(this));
          
          this._oPersonalizationContainer.done(function (oPersonalizationContainer) {
              var oPersonalizationVariantSet = {};
              if (!(oPersonalizationContainer.containsVariantSet("MyAppVariants"))) {
                   oPersonalizationContainer.addVariantSet("MyAppVariants");
              }
      
              oPersonalizationVariantSet = oPersonalizationContainer.getVariantSet("MyAppVariants");
              
              aRenamedVariants.forEach(function (oRenamedVariant) {
                  var oVariant = oPersonalizationVariantSet.getVariant(oRenamedVariant.key);
                  oVariant._oVariantName = oRenamedVariant.name;
              });
      
              oPersonalizationContainer.save().fail(function () {
                  // Error handling
              }.bind(this));
          }.bind(this));
      },
  • Hi,

    Can we save the “variant” in backend? When User logged in and launch the app, he can see the variants which he had saved last time?  So how is this possible? Do we need to send the variants to backend?

  • Hi together,

    Nice tutorial

    I have a short question: If I want to save a variant as the standard variant it works until I close the app, if I open the App again the standard variant is not there anymore (the first one is selected as standard).

    I think I have to save the standard variant somewhere? Does anybody know where or how?

    Many Thanks in advanced

  • Hi Anjani,

    I implemented the logic as per your blog. But now i want to enable this variant management is base on user. How to do that?

    I enabled showShare option, but i dont know how to implement?

  • Hi Anjani,

    I followed your blog to implement variant management. Now i facing issue with setting the default variant for application. After setting the default variant from control once application is reload the default vaiant setting to standard vairant not selected variant.

    for default variant i wrote the same what have gave.

     

    defaultVariant: function (aVariantKeys, fnCallback) {
    var oPersonalizationVariantSet = {};
    this._oPersonalizationContainer.fail(function () {
    //handle failure case
    });
    this._oPersonalizationContainer.done(function (oPersonalizationContainer) {
    if (!(oPersonalizationContainer.containsVariantSet(“MyApplicationVariants”))) {
    oPersonalizationContainer.addVariantSet(“MyApplicationVariants”);
    }
    oPersonalizationVariantSet = oPersonalizationContainer.getVariantSet(“MyApplicationVariants”);

    if (aVariantKeys !== “*standard*”) {
    oPersonalizationVariantSet.setCurrentVariantKey(aVariantKeys);
    } else {
    oPersonalizationVariantSet.setCurrentVariantKey(null);
    var prod = sap.ui.getCore().byId(“product”);
    var plants = sap.ui.getCore().byId(“plants”);
    var manufact = sap.ui.getCore().byId(“manufacturing”);
    var location = sap.ui.getCore().byId(“location”);
    var change = sap.ui.getCore().byId(“change”);
    var Submission = sap.ui.getCore().byId(“Submission”);
    prod.setSelectedKeys();
    plants.setSelectedKeys();
    manufact.setSelectedKeys();
    location.setSelectedKeys();
    change.setSelectedKeys();
    Submission.setSelectedKeys();
    }
    oPersonalizationContainer.save().fail(function () {
    //handle failure case
    fnCallback(false);
    }).done(function () {
    fnCallback(true);
    }.bind(this));
    }.bind(this));
    },

     

    this is my code wrote

    Can you help in this.

    • Hi,

      I know it’s late but for the others, this is what I did.

      I set a custom value named Default for every variant. Zero or one of them will have its value equal to true (zero when standard is the default), the rest have the value false.

      _setNewDefaultVariantKey: function (sNewDefaultVariantKey) {
          this._oPersonalizationContainer.done(function (oPersonalizationContainer) {
              var oPersonalizationVariantSet,
                  oVariant;
                  
              if (!(oPersonalizationContainer.containsVariantSet('MyApplicationVariants'))) {
                  oPersonalizationContainer.addVariantSet('MyApplicationVariants');
              }
              oPersonalizationVariantSet = oPersonalizationContainer.getVariantSet('MyApplicationVariants');
              
              oVariant = oPersonalizationVariantSet.getVariant(sNewDefaultVariantKey);
              
              oPersonalizationVariantSet.getVariantKeys().forEach(function (sKey) {
                  oPersonalizationVariantSet.getVariant(sKey).setItemValue("Default", false);
              });
              
              if (oVariant) { // It is not the standard one
                  oVariant.setItemValue("Default", true);
              }
              
              oPersonalizationContainer.save().fail(function () {
                  // Error handling
              }.bind(this));
          }.bind(this));
      }

       

      When I save a variant I added:

      if (bDefault) {
          oPersonalizationVariantSet.getVariantKeys().forEach(function (sKey) {
              oPersonalizationVariantSet.getVariant(sKey).setItemValue("Default", false);
          });
          
          oVariant.setItemValue("Default", true);
      }

      Where bDefault = oEvent.getParameter(“def”) at the beginning of the save function.

      And in the getAllVariants function I set the default variant for variant management control and also I change the selection to that. Note that setSelectionKey does not work for me but setInitialSelectionKey does.

      if (oVariant.getItemValue("Default")) {
          this.getView().byId("variantManagement").setDefaultVariantKey(sKey);
          this.getView().byId("variantManagement").setInitialSelectionKey(sKey);
      }
  • Hey,

    Thanks for the informative blog.

     

    I am trying to implement this but facing an issue.

    sap.ushell.Container is undefined. any idea how to solve this?

     

  • Anjani,

    Thanks for the information.  How do you populate oSelectedFilterData?  I’ve tried using the FilterBar object itself for that parameter and FilterBar.getFilterGroupItems(), but neither of those worked.

    Thanks,
    Michael