Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
AshishAnand
Employee
Employee
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.
24 Comments