Skip to Content
Technical Articles

Overview page (OVP) developer extension

As part of this blog series, we have already learned about how to configure different cards for an overview page. In this blog, I’ll discuss how an application developer can extend the standard overview page to cater to some of the custom needs. OVP has provided different extension point (breakout) which we will be discussing in detail.

Custom global actions

OVP provides a “share” button by default on the top level of smart filter bar. If you want to add some global action buttons to it, please follow the following steps:

  1. Right click on the project –> New –> Extension
  2. In Template selection pop up, select Overview page extension
  3. in extension setting pop up, choose “Global Actions” and click next

After completing the above three steps, the Web-IDE extension wizard has done following things for you in the background:

  1. Created custom.controller.js and customAction.fragment.xml file under web-app –> ext folder of your project
  2. Updated the manifest.json file to add the newly created controller and view extension.
    "extends": {
    			"extensions": {
    				"sap.ui.controllerExtensions": {
    					"sap.ovp.app.Main": {
    						"controllerName": "demo.ovp.BusinessOverview.ext.custom"
    					}
    				},
    				"sap.ui.viewExtensions": {
    					"sap.ovp.app.Main": {
    						"SmartFilterBarGlobalActionExtension": {
    							"className": "sap.ui.core.Fragment",
    							"fragmentName": "demo.ovp.BusinessOverview.ext.customAction",
    							"type": "XML"
    						}
    					}
    				}
    			}
    		},​

in customAction.fragment.xml file, you can add any number of sap.m.button control and it will appear as custom global action buttons in your OVP application.

<core:FragmentDefinition xmlns="sap.m" xmlns:smartfilterbar="sap.ui.comp.smartfilterbar" xmlns:core="sap.ui.core">
	<Button text="Action1" press="handleCustomAction" type="Transparent"></Button>
	<Button text="Action2" press="handleCustomAction" type="Transparent"></Button>
</core:FragmentDefinition>

in custom.controller.js file you can define event handlers for the “press” event of your custom buttons

handleCustomAction: function () {
				var msg = 'Custom Global Action clicked';
	            MessageToast.show(msg);
		}

Custom Filter

Apart from the attributes of the globalFilterEntityType, the application developer can add some custom filter fields to the smart filter bar of OVP application via the following steps:

  1. Follow Step 1 and 2 as similar for “Custom global filters” (mentioned in the above section)
  2. in step 3, select “Filter” instead of “Global Actions”

After completing the above three steps, the Web-IDE extension wizard has done following things for you in the background:

  1. Created customFilter.fragment.xml file under web-app –> ext folder of your project
  2. Updated the manifest.json file to add the newly created controller and view extension.
    "SmartFilterBarControlConfigurationExtension|GlobalFilters": {
    							"className": "sap.ui.core.Fragment",
    							"fragmentName": "demo.ovp.BusinessOverview.ext.customFilter",
    							"type": "XML"
    						}​

You can define any number of custom filter field in the customFilter.fragment.xml file.

Also, you need to override the following method in your custom.controller.js file to make these custom filters work in sync with your OVP application:

getCustomFilters()

This method returns a filter (sap.ui.model.Filter) to the main OVP application, this custom filter will get added to the standard filters of the OVP application. If we have defined more than one custom filter, then all the filters should be clubbed and returned as one filter.

getCustomFilters: function () {
			var oValue1 = this.oView.byId("ProductID").getValue();
			var oValue2 = this.oView.byId("SalesOrderID").getValue();

			var aFilters = [],
				oFilter1, oFilter2;

			if (oValue1) {
				oFilter1 = new Filter({
					path: "ProductID",
					operator: "EQ",
					value1: oValue1
				});
				aFilters.push(oFilter1);
			}

			if (oValue2) {
				oFilter2 = new Filter({
					path: "SalesOrderID",
					operator: "EQ",
					value1: oValue2
				});
				aFilters.push(oFilter2);
			}

			if (aFilters && aFilters.length > 0) {
				return (new Filter(aFilters, true));
			}
		},

This method can also be very useful when we need to set the filter for two different unrelated propeties.

getCustomAppStateDataExtension(oCustomData)

This method returns custom filter data so that app-state can be formed out of it.

getCustomAppStateDataExtension: function (oCustomData) {
			var oCustomField1 = this.oView.byId("ProductID");
            var oCustomField2 = this.oView.byId("SalesOrderID");
            if (oCustomField1) {
                oCustomData.ProductID = oCustomField1.getValue();
            }
            if (oCustomField2) {
                oCustomData.SalesOrderID = oCustomField2.getValue();
            }
            return oCustomData;
		},

restoreCustomAppStateDataExtension(oCustomData)

This method restores the custom filter data.

restoreCustomAppStateDataExtension: function (oCustomData) {
			var oCustomField1 = this.oView.byId("ProductID");
			oCustomField1.setValue();

			var oCustomField2 = this.oView.byId("SalesOrderID");
			oCustomField2.setValue();

			if (oCustomData) {

				if (oCustomData.ProductID) {
					oCustomField1.setValue(oCustomData.ProductID);
				}

				if (oCustomData.SalesOrderID) {
					oCustomField2.setValue(oCustomData.SalesOrderID);
				}
			}
		},

modifyStartupExtension(oCustomSelectionVariant)

This method can be used to set the initial value of the filters dynamically.

modifyStartupExtension: function (oCustomSelectionVariant) {
			oCustomSelectionVariant.addSelectOption("SupplierName", "I", "EQ", "Talpa");
		},

Custom Navigation params

In order to add some custom navigation parameters on intent based navigation for a card, we need to follow the following steps:

  1. add card setting “customParams” to the card
    "card01": {
    				"model": "GWSAMPLE_BASIC",
    				"template": "sap.ovp.cards.list",
    				"settings": {
    					"title": "{{card01_title}}",
    					"subTitle": "Standard List card - Standard flavour",
    					"entitySet": "ProductSet",
    					"listType": "condensed",
    					"listFlavor": "standard",
    					"sortBy": "Availability_Status",
    					"sortOrder": "Descending",
    					"annotationPath": "com.sap.vocabularies.UI.v1.LineItem",
    					"identificationAnnotationPath": "com.sap.vocabularies.UI.v1.Identification#productHeader1",
    					"addODataSelect": true,
    					"stopResizing": false,
    					"customParams" "getParameters",
    					"defaultSpan": {
    						"rows": 5,
    						"cols": 1,
    						"showOnlyHeader": false
    					}
    				}
    			}​
  2. Override method onCustomParams in your custom.controller.js file. This method returns a function.
    getParameters: function(oNavigateParams,oSelectionVariantParams) {
                var aCustomSelectionVariant = [];
                var aSelectOptions = oSelectionVariantParams.getSelectOptionsPropertyNames();
                if(aSelectOptions.indexOf("SupplierName")!=-1) {
                    var aSupplierFilter = oSelectionVariantParams.getSelectOption("SupplierName");
                    var sSupplierFilterValue = aSupplierFilter[0].Low;
                    aSupplierFilter[0].Low = "";
                }
                var oSupplierName = {
                  path: "SupplierName",
                    operator: "EQ",
                    value1: "",
                    value2: null,
                    sign: "I"
                };
                var oLandFilter = {
                  path: "Land1",
                    operator: "EQ",
                    value1: sSupplierFilterValue,
                    value2: null,
                    sign: "I"
                };
                var oCustomSelectionVariant = {
                    path: "TaxTarifCode",
                    operator: "EQ",
                    value1: 5,
                    value2: null,
                    sign: "I"
                };
                aCustomSelectionVariant.push(oCustomSelectionVariant);
                aCustomSelectionVariant.push(oLandFilter);
                aCustomSelectionVariant.push(oSupplierName);
                return {
                    selectionVariant: aCustomSelectionVariant,
                    ignoreEmptyString: true
                };
            },
    		
    		onCustomParams: function (sCustomParams) {
    			if (sCustomParams === "getParameters") {
    	                return this.getParameters;
    	            } else if (sCustomParams === "param2") {
    	                return this.param2;
    	            }
    		},​

    As you must have noticed in the above example, the onCustomParams method returns function fo signature:

    • Input parameters:
      1.  oContextData: This contains information (property, value pairs) about the current context, Eg, if a list line item is clicked, then it carries info about that line.
      2. oSelectionData (optional): This contains information on card filters and Global filters. We can also manipulate existing selection variant of the card.
    • Return Type: An object with the following attributes:
      1.  aSelectionVariant: An array of objects containing custom parameters. Each object should have properties path, operator, value1, value2 and sign.
      2.  bIgnoreEmptyString :  a flag whether to ignore empty string in navigation parameters/selection variant.
        the ignoreEmptyString flag will remove all the parameters/selection variant coming from the global filter, card level filters and custom filters

Custom Navigation target

This navigation is used to allow the developer to have different navigation behaviour from different areas of the card.  In order to achieve this method “doCustomNavigation” method in your custom.controller.js.

/************************* Handler for custom navigation ************************************************
		 
		 * This function takes the standard navigation entry details (if present) for a particular card and context
		 * and return a new/modified custom navigation entry to the core. The core will then use the custom
		 * navigation entry to perform navigation
		 * @param sCardId  : Card id as defined in manifest for a card
		 * @param oContext : Context of line item that is clicked (empty for header click)
		 * @param oNavigationEntry : Custom navigation entry to be used for navigation
		 * @returns {object} : Properties are {type, semanticObject, action, url, label}
		 * @public
		 **/

		doCustomNavigation: function (sCardId, oContext, oNavigationEntry) {
			var oCustomNavigationEntry;
		    var oEntity = oContext && oContext.sPath && oContext.getProperty && oContext.getProperty(oContext.sPath);
		    if (sCardId === "card001" && oEntity && oEntity.PurchaseOrder === "4500003575") {
		        oCustomNavigationEntry = {};
		        oCustomNavigationEntry.type = "com.sap.vocabularies.UI.v1.DataFieldForIntentBasedNavigation";
		        oCustomNavigationEntry.semanticObject = "Action";
		        oCustomNavigationEntry.action = "toappnavsample";
		        oCustomNavigationEntry.url = ""; //Only required when type is DataFieldWithUrl
		        oCustomNavigationEntry.label = ""; //Optional
		    }
		    return oCustomNavigationEntry;

		},

Custom Action for stack card

We have already discussed that stack card can have some action button at the footer area. It is also possible for the application developer to add custom buttons by following the below steps:

  1. add the property “customAction” to the card settings of the stack card
    "card9": {
    				"model": "GWSAMPLE_BASIC",
    				"template": "sap.ovp.cards.stack",
    				"settings": {
    					"title": "{{card9_title}}",
    					"entitySet": "SalesOrderSet",
    					"subTitle": "Open orders to approve",
    					"addODataSelect": false,
    					"objectStreamCardsSettings": {
    						"annotationPath": "com.sap.vocabularies.UI.v1.Facets#stack",
    						"customActions": [{
    							"text": "action 1",
    							"press": "press1",
    							"position": 1
    						}, {
    							"text": "action 2 ",
    							"press": "press1",
    							"position": 5
    						} {
    							"text": "action 3",
    							"press": "press1",
    							"position": 10
    						} {
    							"text": "action 4",
    							"press": "press1",
    							"position": 20
    						}]
    					},
    					"identificationAnnotationPath": "com.sap.vocabularies.UI.v1.Identification#header,com.sap.vocabularies.UI.v1.Identification#card"
    				}
    			}​
  2. override method onCustomActionPress in your custom.controller.js. this method accepts one argument i.e. value defined in “press” property of customAction card setting. This method should return another event handler method for the press of the custom action button.
    onCustomActionPress: function (sCustomAction) {
    				if (sCustomAction === "press1") {
    		                return this.press1;
    		            } else if (sCustomAction === "press2") {
    		                return this.press2;
    		            }
    		},
    		
    		press1: function(oEvent) {
    		            window.open("https://www.google.co.in");
    		        },
    		
    		        press2: function(oEvent) {
    		            window.open("http://www.sap.com/index.html");
    		        },​

Custom Cards

OVP framework also allows the application developer to define their own card type and use them in their OVP application. I’ll discuss this in my next blog of this blog series.

7 Comments
You must be Logged on to comment or reply to a post.
  • Hello Ashish Anand

    Thanks for the nice blog. Can you please let me know is it possible to extend Procurement OverView App or not . Because , when I am trying to extend the app through WebIDe , I am getting a message “There must be atleast one XML View matching with its controllers ”

     

    How to extend this Procurement OverView App?

    • Hi ,

       

      as of now its not possible to extend the shipped apps via web ide. Only app developer  who is developing the application using OVP library can use extensions provided by OVP to do some customisation

       

      thanks and regards

      ashish

       

      • Hello Ashish Anand,
        Thanks for the reply . But one strange thing which i couldn’t understand is,  On CLick of Card , It is navigating to another application through UI Identificatin -> Data Field for Intent Based Navigation.
        I am seeing clearly Semantic Object & Action of the new application as well. So I am just trying to configure my New Custom App for this Semantic Object Action Pair in my system. Still from the Card of Procurement overview App, I am not able to launch my custom app…
          • Hi Ashish Anand ,

            Thanks for the reply . Actually on click of card, it is navigating to new app through semantic object and action pair.

             

            I created in system with the same set of semantic object and action pair ,different app .But it is always navigating to the original app but not to the app which i configured .

             

            Eventhough i configured with identical semantic object and action combination. Later ,I tried to change the standard catalog semantic object and action pair and on click of card , it is now navigating to the app which i wanted.

            Not sure , why and how SAP is preferring the standard catalog semantic object and action pair even though customer has a different app configured for the same Intent. 

             

             

             

          • Hi pawan,

            im not much of an expert on FLP configuration but as per my understanding  every application should have unique pair semantic object and action.

            Why don’t you give your custom application an unique intend and configure the same in your OVP navigation.

            This should work. Best of luck

            thanks and regards

            ashish