Technical Articles
10 Interesting hacks for UI5 apps using Fiori Elements (Object Page and List Report Floorplans)
Hope you all are enjoying the S/4HANA landscape and stretching the boundaries of the new dictionary objects – ABAP CDS and AMDP. In this blog I will share some of the techniques that I have learned while using Fiori Elements over the last few years.
The Backend as usual consists of ABAP CDS views which I have referenced in a oData service(SEGW). This gives me the flexibility to have all the CRUD operations at one place and also to put some oData annotations in MPC. Let’s concentrate on the Frontend side for now which is the focus of this blog.
- Master data lock Using annotations
This is relevant to transnational apps. In list report some of the records could be editable while others are not (say based on a status or authorization). One way of handling updates is through the backend API at the time of save and display appropriate error message on the app. But a better way is to use the capability annotations to associate the editable property to a field. See the source code. Please note these annotations are at the entity set level.
<Annotations Target="ZCUSTOMORDER_SRV.ZCUSTOMORDER_SRV_Entities/zcustom_order">
<Annotation Term="Capabilities.UpdateRestrictions">
<Record Type="Capabilities.UpdateRestrictionsType">
<PropertyValue Property="Updatable" Path="phas0"/>
</Record>
</Annotation>
<Annotation Term="Capabilities.DeleteRestrictions">
<Record Type="Capabilities.DeleteRestrictionsType">
<PropertyValue Property="Deletable" Path="phas0"/>
</Record>
</Annotation>
</Annotations>
- Automatic value help for Filters and Object Page fields
If we need to use value help popup (associated with each editable field) we have to press the “Go” button each time. It also slows down a user if they want to do the data entry in the app quickly. One option was to use drop downs but then we loose the ability to enter filter criterion. The solution is to use the “configuration” aggregation for smart fields and “controlConfiguration” aggregation for smart filter fields. The id of the controls for apps that use Fiori elements can be quite big as you will notice.
//Auto value help logic for Smart Filter
var smFilt = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--listReportFilter");
var conConfig = smFilt.getControlConfiguration();
conConfig.forEach(function(item, idx, arr){
smFilt.removeControlConfiguration(item);
item.setPreventInitialDataFetchInValueHelpDialog(false);
smFilt.addControlConfiguration(item);
}, this);
//Automatic value help for Object Page smart field
var fld = this.oView.byId("zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--RF1::qmnum::Field");
if (fld) {
var oConfig = fld.getConfiguration();
if (!oConfig) {
oConfig = new sap.ui.comp.smartfield.Configuration();
}
oConfig.setPreventInitialDataFetchInValueHelpDialog(false);
oConfig.setDisplayBehaviour(sap.ui.comp.smartfield.DisplayBehaviour.descriptionAndId);
fld.setConfiguration(oConfig);
}
- Charts as a tab in list report
This is a comparatively new feature(available only UI5 library version 1.60 onward). How to get multiple tabs in list report using Selection Variants – Refer to a detailed blog by Saurabh Mathur – Link
The trick for charts is to use a Presentation variant instead (or a selectionPresentation variant). One problem I faced while implementing this approach was that I had to explicitly load the Chart entity set(in list report onInit() method ) as it does not load automatically.
onInit: function(){
//Somehow the chart entity is not called automatically so we need to call it explicitly to load
this._loadChart();
},
_loadChart: function(){
var url = "/zcustom_order_chart";
var oModel = this.getOwnerComponent().getModel();
var params = {
async: false,
success: function (oData, controller) {
//Do nothing. The Smart chart will automatically read it.
sap.ui.core.BusyIndicator.hide();
},
error: function (oError) {
sap.ui.core.BusyIndicator.hide();
}
};
oModel.read(url, params);
}
- Navigation to external apps passing parameters and preferred mode.
This was a requirement for me for some time specially to pass parameters. The trick here is to set the inbound parameters in the manifest file of the target app. –
- Dynamic default filters(Static default values are already supported through annotations)
We can set Dynamic values as default filter values using the method setDataSuiteFormat() of the smart filter bar. Check out the onAfterRendering method of ListReportExt.controller.js file. This is convenient since we can set only static or hardcoded values using annotations as of now(Look for @Consumption.filter.defaultValue in the CDS view zcustom_order at the end)
onAfterRendering: function () {
// Current timestamp set as default filter for order start but this way we can set any field dynamically
var smFilt = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--listReportFilter"
);
var dat = new Date();//Java script date object
var datStr = dat.toISOString(); // Convert it to format that SAP understands
var jsonString =
'{"SelectionVariantID":"","Parameters":[{"PropertyName":"orderstart","PropertyValue":"' + datStr +'"}]}';
smFilt.setDataSuiteFormat(jsonString);
}
- Enhancing a standard framework button
It’s a common requirement to enhance a standard SAP framework button. There could be a few reasons for that like controlling the edit or display behaviour of fragment built as part of object page section extension. The best way to proceed with this is to attach a press event to the button and write the logic in the function call back.
onAfterRendering: function () {
this._oEditButton = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--edit");
this._oEditButton.attachPress(this.onEditPress);
},
onEditPress : function(){
sap.m.MessageToast.show("Edit button pressed");
},
7. Enhancing a smart field with hyperlink.
This is like enhancing the Standard button. We could potentially do this with annotations like UI.fieldGroup.type. Check the CDS annotation documentation for more details. But the annotation approach is too restrictive. We can alternatively attach a press event to the smart field and handle it in the controller. This way we can pass multiple parameters and preferredMode to the target app.
onNotifPress : function(){
var sPath = that.getView().getBindingContext().getPath();
var notifNo = that.getView().getModel().getProperty(sPath + "/qmnum");
var oNavControl = that.extensionAPI.getNavigationController();
oNavControl.navigateExternal("Notification", {
qmnum: notifNo
});
}
8. Filter facet –
This is another cool local annotation. When reusing the CDS views for value help the UI.Fieldgroup qualifiers make the screen look very cluttered. See the screen shot.
The solution is to use the Filter Facet which removes all the unnecessary grouping in filter.Check out the annotation file at the end.
- Add reference to custom library and test inter-app navigation in webide testing without deployment to front end server.
I had written a blog on building custom libraries some time back – link
Now it is even simpler with SAP template in WEBIDE.
This way you can refer to your custom libraries in workspace or Frontend server and still test the app in WEBIDE itself.
Elina Visoki has written an excellent blog on app to app navigation – Link
Only thing you need to be careful about is maintaining the Inbound Semantic Object and Action in manifest. If you are going to deploy to Frontend server maintain the same in /UI2/SEMOBJ transaction.Lastly run FLPSandbox app instead of your own app to test it.
- Using Internet APIs like Google charts
In this last item I want to touch upon the use of internet APIs. I faced a lot of issues with this in past because if I want to use some internet APIs and deploy the app on Fiori Launchpad of Frontend server I get CORS(Cross Origin Resource Sharing) issues. You can find loads of information about that on internet.
Earlier I was using the “registerModulePath” and “require” which works in WEBIDE but fail to load the APIs when the app is deployed on Frontend server.
jQuery.sap.registerModulePath("google", "https://www.gstatic.com/charts/loader");
jQuery.sap.require("google");
The new method I discovered which works without issue in our On-Premise Frontend server is includeScript –
jQuery.sap.includeScript("https://www.gstatic.com/charts/loader.js", "NewId", function () {
google.charts.load('current', {'packages': ['gauge']});
// Put rest of the logic to build the chart
});
Application Demo
Putting it all together –
Custom Order CDS View
@AbapCatalog.sqlViewName: 'ZCUSTORD'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Custom Order'
@ObjectModel.createEnabled: true
@ObjectModel.deleteEnabled: true
@ObjectModel.updateEnabled: true
define view zcustom_order
as select from zcustomorder
association [* ] to zcustom_notif as _NotifHelp on _NotifHelp.qmnum = zcustomorder.qmnum
{
@UI : {
lineItem: [{ position: 10 }],
selectionField: [{ position: 10 }],
fieldGroup: [{
qualifier: 'Header1',
position : 10
},
{
qualifier: 'Overview1',
position : 10
}]
}
key aufnr,
@UI : {
lineItem: { position: 20 },
selectionField: { position: 20 },
fieldGroup: {
qualifier: 'Overview1',
position : 20
}
}
ktext,
@UI : {
lineItem: [{ position: 30 }],
selectionField: [{ position: 30 }],
fieldGroup: {
qualifier: 'Overview2',
position : 10
}
}
auart,
@UI : {
lineItem: [{ position: 40 }],
selectionField: [{ position: 40 }],
fieldGroup: {
qualifier: 'Overview2',
position : 20
}
}
@Consumption.filter.defaultValue: '30'
auftyp,
@UI : {
lineItem: [{ position: 50 }],
selectionField: [{ position: 50 }],
fieldGroup: {
qualifier: 'Overview3',
position : 10
}
}
werks,
@UI : {
lineItem: [{ position: 60 }],
selectionField: [{ position: 60 }],
fieldGroup: {
qualifier: 'Overview4',
position : 20
}
}
phas0,
@UI : {
lineItem: [{ position: 10 }],
selectionField: { position: 70 },
fieldGroup: {
qualifier: 'Overview4',
position : 10
}
}
@Consumption.valueHelp: '_NotifHelp'
qmnum,
@UI : {
lineItem: [{ position: 10 }],
selectionField: { position: 80 },
fieldGroup: {
qualifier: 'Overview3',
position : 20
}
}
@Consumption.filter: {selectionType : #SINGLE, multipleSelections: false}
@EndUserText.label: 'Order Start Date'
orderstart,
_NotifHelp
}
Chart CDS View –
@AbapCatalog.sqlViewName: 'ZCUSTORDCHART'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Custom order chart'
@UI.chart: [{
title: 'Availability Information',
qualifier: 'Chart1',
chartType: #PIE,
dimensions: [ 'OrderStatus' ],
measures: [ 'Measure' ]
}]
define view zcustom_order_chart as select from zcustom_order {
key auftyp as OrderCatagory,
key case phas0
when 'X' then 'Open'
else 'Closed' end as OrderStatus,
count(*) as Measure
} group by phas0, auftyp
Custom Notification CDS View
@AbapCatalog.sqlViewName: 'ZCUSTNOTIF'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@OData.publish: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Custom notification'
@ObjectModel.createEnabled: true
@ObjectModel.deleteEnabled: true
@ObjectModel.updateEnabled: true
define view zcustom_notif
as select from zcustomnotif
{
@UI : {
lineItem: [{position: 10 }],
selectionField: [{position: 10}],
fieldGroup: [{position: 10,
qualifier: 'Overview1' },{position: 10, qualifier: 'Header1'}]
}
key qmnum,
@UI : {fieldGroup: [{position: 10,
qualifier: 'Overview2' }],
selectionField: [{position: 20}],
lineItem: [{position: 20 }]}
qmtxt,
@UI : {fieldGroup: [{position: 10,
qualifier: 'Overview3' }],
selectionField: [{position: 30}],
lineItem: [{position: 30 }]}
qmdat,
@UI : {fieldGroup: [{position: 10,
qualifier: 'Overview4' }],
selectionField: [{position: 40}],
lineItem: [{position: 40 }]}
aufnr,
@UI : {fieldGroup: [{position: 20,
qualifier: 'Overview1' }],
selectionField: [{position: 50}],
lineItem: [{position: 50 }]}
qmart
}
Manifest –
{
"_version": "1.8.0",
"sap.app": {
"id": "zcustomorder",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"tags": {
"keywords": []
},
"dataSources": {
"ZCUSTOMORDER_SRV": {
"uri": "/sap/opu/odata/sap/ZCUSTOMORDER_SRV/",
"type": "OData",
"settings": {
"localUri": "localService/ZCUSTOMORDER_SRV/metadata.xml",
"annotations": ["localAnnotations", "ZCUSTOMORDER_ANNO_MDL"]
}
},
"localAnnotations": {
"uri": "annotations/annotations.xml",
"type": "ODataAnnotation",
"settings": {
"localUri": "annotations/annotations.xml"
}
},
"ZCUSTOMORDER_ANNO_MDL": {
"uri": "/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Annotations(TechnicalName='ZCUSTOMORDER_ANNO_MDL',Version='0001')/$value/",
"type": "ODataAnnotation",
"settings": {
"localUri": ""
}
}
},
"offline": false,
"sourceTemplate": {
"id": "servicecatalog.connectivityComponentForManifest",
"version": "0.0.0"
},
"crossNavigation": {
"inbounds": {
"intent1": {
"signature": {
"parameters": {},
"additionalParameters": "allowed"
},
"semanticObject": "zcustord",
"action": "manage"
}
},
"outbounds": {
"Notification": {
"semanticObject": "zcustnot",
"action": "manage"
}
}
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone@2": "",
"tablet": "",
"tablet@2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": ["sap_hcb", "sap_belize"]
},
"sap.ui5": {
"resources": {
"js": [],
"css": []
},
"dependencies": {
"minUI5Version": "1.38.34",
"libs": {},
"components": {}
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"uri": "i18n/i18n.properties"
},
"@i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"uri": "i18n/i18n.properties"
},
"i18n|sap.suite.ui.generic.template.ListReport|zcustom_order": {
"type": "sap.ui.model.resource.ResourceModel",
"uri": "i18n/ListReport/zcustom_order/i18n.properties"
},
"i18n|sap.suite.ui.generic.template.ObjectPage|zcustom_order": {
"type": "sap.ui.model.resource.ResourceModel",
"uri": "i18n/ObjectPage/zcustom_order/i18n.properties"
},
"": {
"type": "sap.ui.model.odata.v2.ODataModel",
"settings": {
"defaultOperationMode": "Server",
"defaultBindingMode": "OneWay",
"defaultCountMode": "Request"
},
"dataSource": "ZCUSTOMORDER_SRV",
"preload": true
}
},
"extends": {
"extensions": {
"sap.ui.controllerExtensions": {
"sap.suite.ui.generic.template.ObjectPage.view.Details": {
"controllerName": "zcustomorder.ext.controller.ObjectPageExt",
"sap.ui.generic.app": {
"zcustom_order": {
"EntitySet": "zcustom_order",
"Header": {
"Actions": {
"Notification": {
"id": "Notification",
"text": "{@i18n>CREATE}",
"press": "onCreateNotification"
}
}
}
}
}
},
"sap.suite.ui.generic.template.ListReport.view.ListReport": {
"controllerName": "zcustomorder.ext.controller.ListReportExt",
"sap.ui.generic.app": {
"zcustom_order": {
"EntitySet": "zcustom_order",
"Actions": {}
}
}
}
}
}
},
"contentDensities": {
"compact": true,
"cozy": false
}
},
"sap.ui.generic.app": {
"_version": "1.3.0",
"settings": {
"forceGlobalRefresh": false
},
"pages": {
"ListReport|zcustom_order": {
"entitySet": "zcustom_order",
"component": {
"name": "sap.suite.ui.generic.template.ListReport",
"list": true,
"settings": {
"smartVariantManagement": true,
"quickVariantSelectionX": {
"showCounts": false,
"enableAutoBinding": false,
"variants": {
"0": {
"key": "t0",
"entitySet": "zcustom_order",
"annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#All"
},
"1": {
"key": "t1",
"entitySet": "zcustom_order",
"annotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#Open"
},
"2": {
"key": "t2",
"entitySet": "zcustom_order_chart",
"annotationPath": "com.sap.vocabularies.UI.v1.PresentationVariant#Chart"
}
}
}
}
},
"pages": {
"ObjectPage|zcustom_order": {
"entitySet": "zcustom_order",
"component": {
"name": "sap.suite.ui.generic.template.ObjectPage"
}
}
}
}
}
},
"sap.platform.hcp": {
"uri": ""
}
}
Local Annotation File –
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:Reference Uri="/sap/bc/ui5_ui5/ui2/ushell/resources/sap/ushell/components/factsheet/vocabularies/UI.xml">
<edmx:Include Alias="UI" Namespace="com.sap.vocabularies.UI.v1"/>
</edmx:Reference>
<edmx:Reference Uri="/sap/opu/odata/sap/ZCUSTOM_ORDER_CDS/$metadata">
<edmx:Include Alias="ZCUSTOM_ORDER_CDS" Namespace="ZCUSTOM_ORDER_CDS"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Aggregation.V1.xml">
<edmx:Include Alias="Aggregation" Namespace="Org.OData.Aggregation.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Authorization.V1.xml">
<edmx:Include Alias="Auth" Namespace="Org.OData.Authorization.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Capabilities.V1.xml">
<edmx:Include Alias="Capabilities" Namespace="Org.OData.Capabilities.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://wiki.scn.sap.com/wiki/download/attachments/448470974/Common.xml?api=v2">
<edmx:Include Alias="Common" Namespace="com.sap.vocabularies.Common.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://wiki.scn.sap.com/wiki/download/attachments/448470971/Communication.xml?api=v2">
<edmx:Include Alias="Communication" Namespace="com.sap.vocabularies.Communication.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml">
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Measures.V1.xml">
<edmx:Include Alias="Measures" Namespace="Org.OData.Measures.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Validation.V1.xml">
<edmx:Include Alias="Validation" Namespace="Org.OData.Validation.V1"/>
</edmx:Reference>
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="zcustomorder.ZCUSTOMORDER_SRV">
<!--===============================================================================
Entity Type from chosen collection
================================================================================-->
<Annotations Target="ZCUSTOMORDER_SRV.zcustom_orderType">
<Annotation Term="UI.SelectionVariant" Qualifier="Open">
<Record Type="UI.SelectionVariantType">
<PropertyValue Property="ID" String="SEL02"/>
<PropertyValue Property="Text" String="{@i18n>OPEN}"/>
<PropertyValue Property="SelectOptions">
<Collection>
<Record Type="UI.SelectOptionType">
<PropertyValue Property="PropertyName" PropertyPath="phas0"/>
<PropertyValue Property="Ranges">
<Collection>
<Record Type="UI.SelectionRangeType">
<PropertyValue Property="Sign" EnumMember="UI.SelectionRangeSignType/I"/>
<PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/EQ"/>
<PropertyValue Property="Low" Bool="true"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="UI.SelectionVariant" Qualifier="All">
<Record Type="UI.SelectionVariantType">
<PropertyValue Property="ID" String="SEL01"/>
<PropertyValue Property="Text" String="{@i18n>ALL}"/>
</Record>
</Annotation>
<Annotation Term="UI.HeaderFacets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Header1"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.Facets">
<Collection>
<Record Type="UI.CollectionFacet">
<PropertyValue Property="ID" String="GeneralInformation"/>
<PropertyValue Property="Label" String="{@i18n>OVERVIEW}"/>
<PropertyValue Property="Facets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Overview1"/>
</Record>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Overview2"/>
</Record>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Overview3"/>
</Record>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Overview4"/>
<PropertyValue Property="ID" String="RF1"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</Annotation>
</Annotations>
<Annotations Target="ZCUSTOMORDER_SRV.ZCUSTOMORDER_SRV_Entities/zcustom_order">
<Annotation Term="Capabilities.UpdateRestrictions">
<Record Type="Capabilities.UpdateRestrictionsType">
<PropertyValue Property="Updatable" Path="phas0"/>
</Record>
</Annotation>
<Annotation Term="Capabilities.DeleteRestrictions">
<Record Type="Capabilities.DeleteRestrictionsType">
<PropertyValue Property="Deletable" Path="phas0"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="ZCUSTOMORDER_SRV.zcustom_order_chartType">
<Annotation Term="UI.PresentationVariant" Qualifier="Chart">
<Record Type="UI.PresentationVariantType">
<PropertyValue Property="Visualizations">
<Collection>
<AnnotationPath>@UI.Chart#Chart1</AnnotationPath>
</Collection>
</PropertyValue>
<PropertyValue Property="ID" String="CH1"/>
<PropertyValue Property="Text" String="{@i18n>CHART}"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="ZCUSTOMORDER_SRV.zcustom_notifType">
<Annotation Term="UI.FilterFacets">
<Collection/>
</Annotation>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
List Report Extension –
sap.ui.controller("zcustomorder.ext.controller.ListReportExt", {
onInit: function(){
//Somehow the chart entity is not called automatically so we need to call it explicitly to load
this._loadChart();
//Auto value help logic for Smart Filter
var smFilt = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--listReportFilter"
);
var conConfig = smFilt.getControlConfiguration();
conConfig.forEach(function(item, idx, arr){
smFilt.removeControlConfiguration(item);
item.setPreventInitialDataFetchInValueHelpDialog(false);
smFilt.addControlConfiguration(item);
}, this);
},
onAfterRendering: function () {
// Current timestamp set as default filter for order start but this way we can set any field dynamically
var smFilt = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ListReport.view.ListReport::zcustom_order--listReportFilter"
);
var dat = new Date();//Java script date object
var datStr = dat.toISOString(); // Convert it to format that SAP understands
var jsonString =
'{"SelectionVariantID":"","Parameters":[{"PropertyName":"orderstart","PropertyValue":"' + datStr +'"}]}';
smFilt.setDataSuiteFormat(jsonString);
},
_loadChart: function(){
var url = "/zcustom_order_chart";
var oModel = this.getOwnerComponent().getModel();
var params = {
async: false,
success: function (oData, controller) {
//Do nothing. The Smart chart will automatically read it.
sap.ui.core.BusyIndicator.hide();
},
error: function (oError) {
sap.ui.core.BusyIndicator.hide();
}
};
oModel.read(url, params);
}
});
Object Page Extension –
sap.ui.controller("zcustomorder.ext.controller.ObjectPageExt", {
onInit: function () {
that = this;
//Automatic value help for Object Page smart field
var fld = this.oView.byId("zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--RF1::qmnum::Field");
if (fld) {
var oConfig = fld.getConfiguration();
if (!oConfig) {
oConfig = new sap.ui.comp.smartfield.Configuration();
}
oConfig.setPreventInitialDataFetchInValueHelpDialog(false);
oConfig.setDisplayBehaviour(sap.ui.comp.smartfield.DisplayBehaviour.descriptionAndId);
fld.setConfiguration(oConfig);
}
//Convert Smart field into URL
var notifFld = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--RF1::qmnum::Field"
);
if (notifFld) {
notifFld.attachPress(this.onNotifPress);
}
},
onNotifPress : function(){
var sPath = that.getView().getBindingContext().getPath();
var notifNo = that.getView().getModel().getProperty(sPath + "/qmnum");
var oNavControl = that.extensionAPI.getNavigationController();
oNavControl.navigateExternal("Notification", {
qmnum: notifNo
});
},
onAfterRendering: function () {
this._oEditButton = this.getView().byId(
"zcustomorder::sap.suite.ui.generic.template.ObjectPage.view.Details::zcustom_order--edit");
this._oEditButton.attachPress(this.onEditPress);
},
onEditPress : function(){
sap.m.MessageToast.show("Edit button pressed");
},
onCreateNotification: function (oEvent) {
var oNavControl = this.extensionAPI.getNavigationController();
var oModel = this.getOwnerComponent().getModel();
var sPath = oEvent.getSource().getBindingContext().getPath();
var notNo = oModel.getProperty(sPath + "/qmnum");
var ordNo = oModel.getProperty(sPath + "/aufnr");
var ordStart = oModel.getProperty(sPath + "/orderstart");
oNavControl.navigateExternal("Notification", {
qmnum: notNo,
aufnr: ordNo,
qmdat: ordStart,
preferredMode: "create"
});
}
});
Hi,
Very interesting. Good job.
Regards.
Nice! Thanks for sharing the tips!!
Love that initial data fetch tip for the smart fields.. sap should have made it easier instead of the manual effort.
Thank you Joseph and Mahesh
Thanks Saurabh. Interesting blog!
I've added this to our Fiori elements wiki https://wiki.scn.sap.com/wiki/display/Fiori/Fiori+elements
Thanks Jocelyn, Hopefully some of the community members will find it useful.
Great stuff Saurabh
Thanks Nabheet Madan
Great blog! Is it possible to create a controller extension that pre-populates field values when clicking the create button from the list report?
Thanks,
Michael
Thankyou Michael Smith
Yes we had a similar requirement in our project. SAP has provided 2 options for providing default values during create -
Link to UI5 SDK.
For our project, we needed more control over the default values(which was read from a config table) so we went with option 1.
Best regards,
Saurabh
My requirement is actually simpler than that (or at least it should be). I simply want to hard-code a default country value into the create page. That country field has a valuelist annotation with a fixed set of 4 country values. Can I add an inbound parameter that is a constant value?
Of course. How I would envision it is that instead of standard "Create" button you would have a custom action in the hitlist of List report. And on press of that you would call the external app using navigation controller with preferred mode "Create" quite similar to how I implemented onCreateNotification() method above but pass a hardcoded value like this-
Hi Saurabh,
Nice blog. I have a requirement in which i am facing some issue on the approach i should take. It’s basically for transnational (fiori elements) app “manage sales contracts” (app id:F1851). The requirement is that when we click on line item radio button for any sales contracts, it should open the dependent materials in another table “Item Display” below that as it’s line items. I have attached the screen below for better understanding.
The issue i am facing as this app is based on CDS annotations and using ” Adaptation Project” option in WEBIDE i am finding it difficult to achieve it. Can you guide if this feature can be achieved by CDS annotation tweaks and if any helpful links you can provide.
We are on S/4Hana 1809 FPS01.
Thanks,
Rakesh
Hi Saurabh,
Excellent blog!
Regards,
Jay