Motivation
Many SAP Screen Personas customers are using the product’s powerful JavaScript scripting engine to extend SAP GUI applications via the SAPUI5 framework. These customers frequently leverage GuiHtmlViewer web application containers to embed custom SAPUI5 applications in SAP Screen Personas flavors, using HTML inline frames and the Cross-Origin Resource Sharing mechanism for data exchange.
The SAP Screen Personas script editor’s primary purpose is to enable input automation by recording or manually defining user interaction sequences using the SAP Screen Personas scripting API and JavaScript. It is not optimized for developing and maintaining custom SAPUI5 code, leading to many customer requests to improve the development experience.
With the SAP Screen Personas 3.0 Support Pack 12 release, we have addressed custom development improvement requests by decoupling SAPUI5 development from SAP Screen Personas scripts with a feature called SAPUI5 applets. The SAPUI5 applets feature is a continuation of SAP Fiori enablement for classic SAP GUI screens rendered with Slipstream Engine.
The purpose of this article is to outline technical considerations when using the SAPUI5 applets feature.
Introducing the SAPUI5 Applets
An SAPUI5 applet is an SAPUI5 SAP Fiori application that is entirely developed, tested, and maintained using appropriate tooling — such as Visual Studio Code, SAP Business Application Studio, or SAP WebIDE — and then deployed on an SAP back-end system and consumed from Slipstream Engine flavors in a single page application environment. Examples of applets could be an SAP Fiori table, a chart, or even a set of services without any user interface (UI).
Once you insert an applet into your flavor, the SAP Screen Personas scripting API can be used to exchange data between SAP GUI runtime and the SAPUI5 applet’s view model.
Some of the advantages of using the SAPUI5 Applets feature over the classic approach that leverages SAPUI5 code directly in flavor scripts include:
- Separation of user input automation from custom SAPUI5 development
- Access to a dedicated SAPUI5 integrated development environment that can be used for custom SAP Fiori development by following SAP-provided best practices
- Improved maintainability, testability, modularity, supportability, and upgradability
- Better performance, since the single page application concept means that the SAPUI5 framework is not required to be loaded and initialized in HTML inline frames
- Simple integration and lifecycle management, since SAPUI5 applet components are managed by Slipstream Engine
The high-level process for creating an SAPUI5 applet and consuming it in an SAP Screen Personas flavor is as follows:
- Define the integration requirements, including the data model and communication means between the SAP GUI runtime and the SAPUI5 applet component.
- Develop the SAPUI5 applet using the SAPUI5 SAP Fiori application project templates and development best practices. The SAPUI5 applet must follow the standard SAP Fiori Model-view-controller application file structure.
- Consider software engineering best practices, such as configuration management and quality assurance .
- Deploy the SAPUI5 applet on an SAP NetWeaver Application Server ABAP back-end system using the SAPUI5 ABAP Repository by following the standard SAPUI5 SAP Fiori on-premise deployment process.
- Create an allowlist entry to enable the deployed SAPUI5 applet to be inserted from the SAP Screen Personas flavor editor. For security reasons, exercise caution and only enable SAPUI5 applets that you trust.
- Insert the enabled SAPUI5 applet into your SAP Screen Personas flavor
- Bind SAPUI5 applets with SAP GUI runtime by creating an SAP Screen Personas script that acts as an interface adapter.
To better illustrate the SAPUI5 applets feature, let’s look at an example scenario.
Example Scenario
In this example, the classic SAP GUI transaction IW29 Display Notifications, rendered in Slipstream Engine, will be customized by replacing the standard grid control with a responsive SAPUI5 SAP Fiori table to significantly improve its functionality on mobile devices.
The high-level business requirements are as follows:
- Ensure that the list of notifications is responsive and automatically adapts to mobile device screens.
- Implement searching, sorting, and filtering capabilities that are easy to use from mobile devices.
- Launch transaction IW53 Display Service Notification when users select a notification row. The selected ID should be prefilled in IW53 based on the row selected in IW29.
- IW53 should be already customized using SAP Screen Personas and Slipstream Engine.
To implement these requirements, we will use the SAP Screen Personas 3.0 SP12 SAPUI5 applets feature to replace the IW29 GuiGridView control with an SAPUI5 sap.m.Table control.
Prerequisites
- The SAPUI5 ABAP repository and the ABAP back-end infrastructure set-up must be completed.
- An ABAP development package must be created for the SAPUI5 application deployment.
- SAP Screen Personas 3.0 Support Pack 12 is required.
- SAPUI5 Development IDE of choice needs to be installed and configured.
- (Optional) UI5 Tooling can be installed
- The necessary PFCG roles to deploy new SAPUI5 applications and access SAP Screen Personas admin transaction are required.
- To simplify date sorting, consider setting the date format to MM/DD/YYYY in SU01.
- The layout of transaction IW29 should be configured to display the following columns:
Column Name | Column Technical name |
Notification | QMNUM |
Notification Type | QMART |
Notification Date | QMDAT |
Priority Text | PRIOKX |
Priority | PRIOK |
Description | QMTXT |
Equipment | EQUNR |
Malfunction Start | AUSVN |
Table 1. IW29 Notification List Visible Columns
Defining the Data Model and Interfaces
The SAPUI5 applet featured in the demo scenario integrates with SAP GUI runtime in the following ways:
- It consumes the notification data directly from the IW29 transaction rendered in Slipstream Engine through the common data model.
- It enables the attachment of an SAP Screen Personas script to the SAPUI5 table row selection event by exposing an external interface.
Data Model
The SAPUI5 applet will leverage the SAPUI5 data-binding to render the dynamic notifications list based on the data structure maintained in the sap.ui.model.json.JSONModel instance.
Here is the JSON data structure target pattern for the demo scenario:
{
"NotificationCollection": [{
"QMNUM": "<String: Notification #1 ID value>",
"QMART": "<String: Notification #1 Type value>",
"QMDAT": "<String: Notification #1 Date value>",
"PRIOKX": "<String: Notification #1 Priority text value>",
"PRIOK": "<String: Notification #1 Priority value>",
"QMTXT": "<String: Notification #1 Description value>",
"EQUNR": "<String: Notification #1 Equipment ID value>",
"AUSVN": "<String: Notification #1 Malfunction Start Date value>"
}, {
"QMNUM": "<String: Notification #n ID value>",
"QMART": "<String: Notification #n Type value>",
"QMDAT": "<String: Notification #n Date value>",
"PRIOKX": "<String: Notification #n Priority text value>",
"PRIOK": "<String: Notification #n Priority value>",
"QMTXT": "<String: Notification #n Description value>",
"EQUNR": "<String: Notification #n Equipment ID value>",
"AUSVN": "<String: Notification #n Malfunction Start Date value>"
}]
}
Each object in the data structure example represents a single table row and the JSON object keys match the technical column names of the IW29 table layout; therefore simplifying the SAP Screen Personas adapter script, since data mapping functionality is not needed.
The SAP Screen Personas script will set the SAPUI5 applet initial data by:
- Traversing the original IW29 table and preparing the data structure object according to the agreed format
- Retrieving the SAPUI5 applet view model instance during the flavor load using the Scripting API
- Setting the created data structure to the SAPUI5 applet’s view model instance and therefore triggering the automatic data-binding update
External Interface
As per the business requirements, the user’s row selection event must be captured by an SAP Screen Personas script that:
- takes the selected notification ID,
- switches the transaction from IW29 to IW53
- skips the notification selection screen by automatically prefilling the selected notification ID
To implement the requirement, the SAPUI5 Applet will feature a sap/ui/core/service/Service class extension that defines an external interface:
- attachSelect(Function: Function, Object: Listener): void – Enables the attachment of a JavaScript function instance that is called when users select a table row
- detachSelect(Function: Function, Object: Listener): void – Detaches the external handler function from the table row selection event
- setSelectedRowById (String sNotificationId): void – Programmatically sets the selected table row by providing the notification ID as an input
It is crucial to mention that the SAPUI5 applets integration with classic web enabled SAP GUI transactions requires the SAP Screen Personas Scripting Engine API to be used as an interface adapter that translates SAPUI5 applet functionality to SAP GUI runtime. When evaluating feasibility of implementing SAPUI5 applets, always consider the SAP Screen Personas scripting API to ensure that such an adapter for the desired functionality can be implemented through the means of SAP Screen Personas scripts.
Building the SAPUI5 Applet
The SAPUI5 applet development process for the demo scenario will require the following steps:
- Creating the SAPUI5 application project structure
- Defining the project configuration in the manifest.json file
- Implementing the Component.js file
- Defining the external component interface by implementing the SelectionService class
- Implementing the SAPUI5 applet XML view
- Implementing the SAPUI5 controller for the view
Creating the Initial SAPUI5 Application Project Structure
- Decide on the configuration management solution. Git will be used here for demonstration purposes
- Create the project folder iw29-mobile-table
- Initialize the SAPUI5 Project structure. UI5 tooling and a Yeoman Easy-ui5 generator can be used for this. Create or generate the following empty SAPUI5 SAP Fiori application project files:
iw29-mobile-table/uimodule/webapp/
- Component.js
- manifest.json
- Formatter.js
- SelectionService.js
- view/
- Table.view.xml
- controller/
- Table.controller.js
- fragments/
- Filter.fragment.xml
- Sort.fragment.xml
Defining the project configuration in the manifest.json file
Open the iw29-mobile-table/uimodule/webapp/manifest.json file and insert the following JSON source code:
{
"_version": "1.0.0",
"sap.app": {
"id": "iw29mobiletable",
"type": "application",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}"
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone@2": "",
"tablet": "",
"tablet@2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
},
"sap.ui5": {
"flexEnabled": false,
"rootView": {
"viewName": "iw29mobiletable.view.Table",
"type": "XML",
"async": true,
"id": "Table"
},
"dependencies": {
"minUI5Version": "1.65.6",
"libs": {
"sap.ui.layout": {},
"sap.ui.core": {},
"sap.m": {},
"sap.ndc": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"DATA": {
"type": "sap.ui.model.json.JSONModel",
"dataSource": "test_model"
}
},
"services": {
"SelectionService": {
"factoryName": "iw29mobiletable.SelectionService"
}
}
}
}
Implementing the Component.js file
Open the iw29-mobile-table/uimodule/webapp/Component.js file and insert the following JavaScript source code:
sap.ui.define([
"sap/ui/core/UIComponent",
"iw29mobiletable/SelectionService"
], function (UIComponent, SelectionService) {
"use strict";
return UIComponent.extend("iw29mobiletable.Component", {
metadata: {
manifest: "json"
},
/**
* The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
* @public
* @override
*/
init: function () {
// call the base component's init function
UIComponent.prototype.init.apply(this, arguments);
},
/*
* @override
* Returns new Service instance that an implements external API inteface
*/
getService : function(sServiceName) {
if(sServiceName === "SelectionService"){
return new SelectionService({
scopeObject: this,
scopeType: "component"
});
}
return null;
}
});
});
Defining the external component interface by implementing the SelectionService class
Open the iw29-mobile-table/uimodule/webapp/SelectionService.js file and insert the following JavaScript source code:
sap.ui.define([
"sap/ui/core/service/Service",
"sap/ui/core/service/ServiceFactory",
"sap/ui/core/service/ServiceFactoryRegistry"
], function (Service, ServiceFactory, ServiceFactoryRegistry) {
"use strict";
var oSelectionService = Service.extend("iw29mobiletable.SelectionService", {
_oEventProvider : null,
_oEventBus : null,
init: function () {
ServiceFactoryRegistry.register("iw29mobiletable.SelectionService", new ServiceFactory(this.getInterface()));
this._oEventProvider = new sap.ui.base.EventProvider();
this._oEventBus = sap.ui.getCore().getEventBus();
//The "select" event is published by the iw29mobiletable.controller.Table controller instance once a table row has been selected
this._oEventBus.subscribe("iw29mobiletable", "select", this._onSelect, this);
},
/*
* @private
* @param {String} sChannel
* @param {String} sId
* @param {Object} oData
* The method propogates the "select" event fired by the iw29mobiletable.controller.Table instance
*/
_onSelect : function(sChannel, sId, oData) {
this._oEventProvider.fireEvent("select", {"id" : oData.id});
},
/*
* @param {Function} fnFuntion
* @param {Object} oListener
* Attach external handler function to the table row selection event
*/
attachSelect : function(fnFuntion, oListener){
this._oEventProvider.attachEvent("select", null, fnFuntion, oListener);
},
/*
* @param {Function} fnFuntion
* @param {Object} oListener
* Detach external handler function from the table row selection event
*/
detachSelect : function(fnFuntion, oListener){
this._oEventProvider.detachEvent("select", fnFuntion, oListener);
},
/*
* @param {String} sNotificationId
* Selects table row by notification id
*/
setSelectedRowById : function(sNotificationId){
this._oEventBus.publish("iw29mobiletable", "selectRow", {
"id": sNotificationId
});
}
});
return oSelectionService;
});
Implementing the SAPUI5 Applet XML view
Open the iw29-mobile-table/uimodule/webapp/view/Table.view.xml file and insert the following XML source code:
<mvc:View controllerName="iw29mobiletable.controller.Table" xmlns:mvc="sap.ui.core.mvc" xmlns:core="sap.ui.core" xmlns="sap.m">
<Table id="idNotificationsTable" inset="false" mode="SingleSelectMaster" selectionChange="onSelect"
items="{ path: 'DATA>/NotificationCollection', sorter: { path: 'Name' } }">
<headerToolbar>
<OverflowToolbar>
<content>
<Title text="Notifications" level="H2"/>
<ToolbarSpacer/>
<SearchField id="searchField" search="onSearch" placeholder="Search by Equipment" width="auto"></SearchField>
<Button tooltip="Group" icon="sap-icon://sort" press="onSort"/>
<Button tooltip="Filter" icon="sap-icon://filter" press="onFilter"/>
</content>
</OverflowToolbar>
</headerToolbar>
<columns>
<Column minScreenWidth="Tablet" demandPopin="true" hAlign="Center">
<Text text="Notification"/>
</Column>
<Column minScreenWidth="Tablet" hAlign="Center">
<Text text="Notification Date"/>
</Column>
<Column minScreenWidth="Tablet" demandPopin="true" hAlign="Center">
<Text text="Description"/>
</Column>
<Column minScreenWidth="Tablet" demandPopin="true" hAlign="Center">
<Text text="Equipment"/>
</Column>
<Column demandPopin="true" hAlign="Center">
<Text text="Malfunction Start Date"/>
</Column>
<Column demandPopin="true" hAlign="Center">
<Text text="Priority"/>
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<ObjectIdentifier title="{DATA>QMNUM}" text="{DATA>QMART}"/>
<Text
text="{ path: 'DATA>QMDAT', type: 'sap.ui.model.type.Date', formatOptions : { pattern : 'MM/dd/yyyy', source : { pattern : 'MM/dd/yyyy' } } }"/>
<Text text="{DATA>QMTXT}"/>
<Text text="{DATA>EQUNR}"/>
<Text
text="{ path: 'DATA>AUSVN', type: 'sap.ui.model.type.Date', formatOptions : { pattern : 'MM/dd/yyyy', source : { pattern : 'MM/dd/yyyy' } } }"/>
<ObjectStatus text="{DATA>PRIOKX}" state="{path : 'DATA>PRIOK', formatter : 'iw29mobiletable.Formatter.priority'}"/>
</cells>
</ColumnListItem>
</items>
</Table>
</mvc:View>
Implementing the SAPUI5 controller for the view
Open the iw29-mobile-table/uimodule/webapp/Formatter.js file and insert the following JavaScript source code:
sap.ui.define(function() {
"use strict";
var Formatter = {
priority : function (sPriority) {
switch(sPriority){
case "3":
return "Warning";
case "2":
case "1":
return "Error";
default:
return "None";
}
}
};
return Formatter;
}, true);
Open the iw29-mobile-table/uimodule/webapp/fragments/Filter.fragment.xml file and insert the following XML source code:
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core">
<ViewSettingsDialog confirm="onFilterConfirmed">
<filterItems>
<ViewSettingsFilterItem text="Type" key="QMART" multiSelect="true">
<items>
<ViewSettingsItem text="M2 - Malfunction report" key="QMART___EQ___M2"/>
<ViewSettingsItem text="S2 - Service request" key="QMART___EQ___S2"/>
<ViewSettingsItem text="S3 - Activity report" key="QMART___EQ___S3"/>
</items>
</ViewSettingsFilterItem>
<ViewSettingsFilterItem text="Priority" key="PRIOK" multiSelect="true">
<items>
<ViewSettingsItem text="1-Very high" key="PRIOK___EQ___1"/>
<ViewSettingsItem text="2-High" key="PRIOK___EQ___2"/>
<ViewSettingsItem text="3-Medium" key="PRIOK___EQ___3"/>
<ViewSettingsItem text="4-Low" key="PRIOK___EQ___4"/>
</items>
</ViewSettingsFilterItem>
<ViewSettingsFilterItem text="Notification Date" key="QMDAT" multiSelect="false">
<items>
<ViewSettingsItem text="Today" key="QMDAT___EQ___TODAY"/>
<ViewSettingsItem text="Within a month" key="QMDAT___BT___TODAY___MONTH"/>
<ViewSettingsItem text="Older than a month" key="QMDAT___LT___MONTH"/>
</items>
</ViewSettingsFilterItem>
<ViewSettingsFilterItem text="Malfunction Date" key="AUSVN" multiSelect="false">
<items>
<ViewSettingsItem text="Today" key="AUSVN___EQ___TODAY"/>
<ViewSettingsItem text="Within a month" key="AUSVN___BT___TODAY___MONTH"/>
<ViewSettingsItem text="Older than a month" key="AUSVN___LT___MONTH"/>
</items>
</ViewSettingsFilterItem>
</filterItems>
</ViewSettingsDialog>
</core:FragmentDefinition>
Open the iw29-mobile-table/uimodule/webapp/fragments/Sort.fragment.xml file and insert the following XML source code:
<core:FragmentDefinition
xmlns="sap.m"
xmlns:core="sap.ui.core">
<ViewSettingsDialog
confirm="onSortConfirm">
<sortItems>
<ViewSettingsItem text="Notification Date" key="QMDAT" selected="true" />
<ViewSettingsItem text="Equipment" key="EQUNR" />
<ViewSettingsItem text="Malfunction Start Date" key="AUSVN" />
<ViewSettingsItem text="Priority" key="PRIOKX" />
</sortItems>
</ViewSettingsDialog>
</core:FragmentDefinition>
Open the iw29-mobile-table/uimodule/webapp/controller/Table.controller.js file and insert the following JavaScript source code:
sap.ui.define([
"/../Formatter",
"sap/ui/core/mvc/Controller",
"sap/ui/model/json/JSONModel",
"sap/ui/model/Filter",
"sap/ui/model/FilterOperator",
"sap/ui/model/Sorter"
], function (Formatter, Controller, JSONModel, Filter, FilterOperator, Sorter, BarcodeScanner) {
"use strict";
var TableController = Controller.extend("iw29mobiletable.controller.Table", {
_oEventBus: null,
_oFilterDialog : null,
_oSortDialog : null,
_oTable : null,
onInit: function () {
this._oEventBus = sap.ui.getCore().getEventBus();
this._oEventBus.subscribe("iw29mobiletable", "selectRow", this.onNotificationSelect, this);
this._oTable = this.byId("idNotificationsTable");
},
/*
* Table row selection handler
* @param {Object} oEvent
*/
onSelect: function (oEvent) {
var oSelectedListItem = oEvent.getParameter("listItem"),
oNotificationCell = oSelectedListItem.getCells()[0],
sNotificationId = oNotificationCell.getTitle();
this._oEventBus.publish("iw29mobiletable", "select", {
"id": sNotificationId
});
},
/*
* @param {String} sChannel
* @param {String} sId
* @param {Object} oData
* Handles Row selection request
*/
onNotificationSelect: function (sChannel, sId, oData) {
var sNotificationId = oData.id;
var sTitle;
var oItem;
var aTableItems = this._oTable.getItems();
var i;
for(i = 0; i < aTableItems.length; i++){
oItem = aTableItems[i];
sTitle = oItem.getCells()[0].getTitle();
if(sTitle === sNotificationId){
this._oTable.setSelectedItem(oItem);
oItem.focus();
return;
}
}
this._oTable.removeSelections(true);
},
/*
* Table search handler
* @param {Object} oEvent
*/
onSearch: function (oEvent) {
var sQuery,
oBindings = this._oTable.getBinding("items");
if (oEvent.getParameters().clearButtonPressed) {
oBindings.filter("");
} else {
sQuery = oEvent.getParameter("query");
if (sQuery && sQuery.length > 0) {
oBindings.filter([new Filter("EQUNR", FilterOperator.Contains, sQuery)]);
}
}
},
/*
* Sort button press handler
*/
onSort: function(){
if (!this._oSortDialog) {
this._oSortDialog = sap.ui.xmlfragment("iw29mobiletable.fragments.Sort", this);
}
this._oSortDialog.open();
},
/*
* Filter button press handler
*/
onFilter: function(){
if (!this._oFilterDialog) {
this._oFilterDialog = sap.ui.xmlfragment("iw29mobiletable.fragments.Filter", this);
}
this._oFilterDialog.open();
},
/*
* Handles table sorting
* @param {Object} oEvent
*/
onSortConfirm : function(oEvent){
var mParams = oEvent.getParameters(),
bDescending = mParams.sortDescending,
sPath = mParams.sortItem.getKey(),
oSorter;
//A custom sorter is required for dates
if(sPath === "QMDAT" || sPath === "AUSVN"){
oSorter = new Sorter(sPath, bDescending, undefined, this._compareDates);
}else{
oSorter = new Sorter(sPath, bDescending);
}
this._oTable.getBinding("items").sort([oSorter]);
},
/**
* Compares two date strings
* @param {String} sDateX
* @param {String} sDateY
* @return {Integer} [-1;1]
*/
_compareDates : function(sDateX, sDateY){
var oDateX = new Date(sDateX),
oDateY = new Date(sDateY);
if(oDateX < oDateY || !oDateY){
return -1;
}
if(oDateX > oDateY || !oDateX){
return 1;
}
return 0;
},
/**
* Converts date constants into dynamic date strings
* @param {String} sValue
* @return {String}
*/
_convertDate : function(sValue){
var oDate = new Date();
switch(sValue){
case "TODAY" :
return oDate.toDateString();
case "MONTH" :
oDate.setMonth(oDate.getMonth() - 1);
return oDate.toDateString();
default :
return sValue;
}
},
/*
* Handles table filtering
* @param {Object} oEvent
*/
onFilterConfirmed : function(oEvent){
var mParams = oEvent.getParameters(),
oBinding = this._oTable.getBinding("items"),
aFilters = [];
mParams.filterItems.forEach(function(oItem) {
var aSplit = oItem.getKey().split("___"),
sPath = aSplit[0],
sOperator = aSplit[1],
sValue1 = aSplit[2],
sValue2 = aSplit[3],
oFilter = new Filter(sPath, sOperator, sValue1, sValue2);
//Custom filter settings for dates
if(sPath === "AUSVN" || sPath === "QMDAT"){
oFilter.oValue1 = this._convertDate(sValue1);
oFilter.sValue2 = this._convertDate(sValue2);
oFilter.fnCompare = this._compareDates;
}
aFilters.push(oFilter);
}.bind(this));
// apply filter settings
oBinding.filter(aFilters);
}
});
return TableController;
});
Deploying the SAPUI5 Applet
To deploy the finished SAPUI5 application in the SAPUI5 ABAP repository, simply follow the Certifications here. For this demonstration, the SAPUI5 applet has been deployed in PERSONAS_TEST_DEMOS package with the name IW29_TABLE assigned.
Creating an Allowlist Entry
To insert and consume the deployed SAPUI5 applet in SAP Screen Personas flavors rendered in Slipstream Engine, an allowlist entry needs to be created. For security reasons, please only enable third-party SAPUI5 applications that are verified and trusted.
To create an allow list entry:
- Navigate to transaction /n/PERSONAS/ADMIN
- Select SAPUI5 Applets under the Whitelists option
- Press Change and then press New Entry
- Enter the SAPUI5 applet Name and Package specified during the deployment. It is possible to use regular expressions
- Save changes
Inserting the SAPUI5 Applet in a Flavor
Once an SAPUI5 applet is permitted, it can be embedded in any web-enabled classic SAP GUI transaction rendered in Slipstream Engine using the flavor editor. For the demo scenario, the IW29 standard GuiGridView control will be replaced with the SAPUI5 applet. To do so:
- Navigate to transaction IW29 using Slipstream Engine
- Press Execute to skip the filter page
- Create a new SAP Screen Personas flavor
- Select and hide the original GuiGridView control
- Select the GuiUserArea container
- Select the Templates tab, then SAPUI5 Applets
- Look for the package containing the SAPUI5 applet specified during the deployment
- Select the desired SAPUI5 applet component
- Check the Stretch to container size option. Doing so will enable the SAPUI5 applet view to take all the available container real estate and dynamically adapt if the container (in this case, GuiUserArea) has been resized, ensuring that the SAPUI5 applet will dynamically adapt its size based on the device screen resolution.
10. Press Done to insert the SAPUI5 applet into the GuiUserArea container
11. Save changes and exit the flavor editor
Binding the SAP GUI runtime with the SAPUI5 applet’s data model
The SAPUI5 applet component will now be rendered in IW29 runtime, however the notifications list will be empty. To bind the data between the SAP GUI runtime and the SAPUI5 applet, we can use the SAP Screen Personas Scripting Engine API.
The following functionality is required:
- Read the original IW29 GuiGridView table in a JavaScript object according to the established data model
- Wait for the SAPUI5 applet asynchronous initialization, then retrieve the SAPUI5 App Component class instance reference and:
- Retrieve the SAPUI5 applets view model class instance
- Set the IW29 runtime data to the SAPUI5 applet view thereby triggering the data-binding update
- Retrieve the SAPUI5 applet SelectionService class instance to access the external API and attach a JavaScript function that handles the SAPUI5 applet row selection event
- Retrieve the SAPUI5 applets view model class instance
The following steps will bind the IW29 runtime with the SAPUI5 applet:
- Select the IW29 flavor containing the SAPUI5 applet in the SAP Screen Personas flavor manager and open the script editor.
- Create a new script. For example: setAppletData
- Insert the following source code.
// Load table data from screen
var fnReadModelData = function (){
var oSelectedTable = session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell");
var aColumns = oSelectedTable.columns;
var aContents = [];
var sSAPColumnName;
var iTopRow, iRowIdx, oRow, i;
if (oSelectedTable.rowCount > 0) {
oSelectedTable.firstVisibleRow = 0;
iTopRow = oSelectedTable.visibleRowCount - 1;
for (iRowIdx = 0; iRowIdx < oSelectedTable.rowCount; iRowIdx++) {
oRow = {};
if (iRowIdx > iTopRow) {
if (iTopRow + oSelectedTable.visibleRowCount > oSelectedTable.rowCount) {
oSelectedTable.firstVisibleRow = oSelectedTable.rowCount - oSelectedTable.visibleRowCount;
} else {
oSelectedTable.firstVisibleRow = iTopRow + 1;
}
iTopRow += oSelectedTable.visibleRowCount;
}
for (i = 0; i < aColumns.length; i++) {
sSAPColumnName = aColumns.elementAt(i).name;
oRow[sSAPColumnName] = oSelectedTable.getCellValue(iRowIdx, sSAPColumnName);
}
aContents.push(oRow);
}
}
return aContents;
};
var oComponent = session.findById("<PLACE YOUR APPLET ID HERE>").getComponent();
oComponent.getService("SelectionService").attachSelect(function(oEvent){
session.utils.put("SELECTED_NOTIFICATION", oEvent.getParameter("id"));
}.bind(this));
//Set the SAPUI5 Applet view model data
oViewModel = oComponent.getModel("DATA");
oViewModel.setData({"NotificationCollection" : fnReadModelData()});
4. Use the Object Selector to select the SAPUI5 applet control and replace the <PLACE YOUR APPLET ID HERE> placeholder featured in the code snippet above with the actual SAPUI5 applet control ID.
5. Save the script and close the script editor.
Once the interface adapter script is finished, it is possible to bind the script with the SAPUI5 applet component load event in the flavor editor:
- Edit the flavor
- Select the SAPUI5 applet control
- Open the Script Assignments dialog (Insert Tab > Script Events)
- Assign the created script to the onAppletComponentLoad event
- Save the changes, exit the flavor editor, and reload the flavor
- The data binding between the SAPUI5 applet and the IW29 runtime is now complete
Further Considerations
- For security reasons, always exercise caution and assess potential risks when embedding third-party functionality through the SAP Screen Personas scripting engine and the SAPUI5 applets feature.
- SAPUI5 applets require SAPUI5 runtime, therefore only Slipstream Engine supports the feature.
- The SAPUI5 applets feature uses the same SAPUI5 version that is loaded with Slipstream Engine. Make sure your custom applets are compatible with the target SAPUI5 version, especially when SAP Fiori launchpad integration and different SAPUI5 themes are being used.
- For SAP Fiori launchpad HUB deployment, it is recommended to deploy SAPUI5 applets on the Gateway server and create an allowlist entry for each back-end system hosting Slipstream Engine and consuming SAPUI5 applets.
- SAPUI5 applets are considered custom development, therefore the SAP Screen Personas team cannot provide technical support or consultation regarding additional functionality enabled through the means of the SAPUI5 applets feature.