
What will be covered in the article:
There are some typical use cases of enhancing Fiori apps. Most of the sources draw attention only to one part of Adaptation projects. That’s why the decision was made to combine backend & frontend work steps in one manual.
Prerequisites:
First off all let’s assume that you received functional specification to adapt F3365 Fiori app (Record Inspection Results in Table Form).
Where to start? Google of course!
In the top of the search list you can find the link looks like
https://fioriappslibrary.hana.ondemand.com/sap/fix/externalViewer/#/detail/Apps('F3365')
You can replace F3365 to any App ID you received from functional
Now Go to IMPLEMENTATION INFORMATION -> Configuration
Here we need Technical Name (QM_MLTPL_RR_S1) & SAP UI5 Component (i2d.qm.inspmltpl.resultsrecords1)
Why do we need a technical name? To read XML & JS code. Of course sometimes you can do it directly in a browser. But is better to read all comments in JS code.
Launch /UI5/UI5_REPOSITORY_LOAD program (or BSP_UPDATE_MIMEREPOS in older systems) & download app code to any folder.
Here the 2 most important folders are:
*-dbg.controller.js non minimized ordinary JS code with comments
XML views. Also in sub folder \view\fragments\ some dynamic objects like dialogs and other reusable UI parts are located there.
Another important file is manifest.json but let’s talk about it next time
Now let’s launch Fiori launchpad & find the F3365 app
Before launching app press F12(or Ctrl+Shift+I) & type batch word in the Network tab
If you noticed in the address bar there is no /sap/bc/ui5_ui5/sap/qm_mltpl_rr_s1 (Path to ICF Node in the 1st screenshot). This path used indirectly via special mechanism & in the URL you can see InspectionCharacteristic-recordMltplResults (so called Semantic Object-Action). We later use this data to create our own tile in Fiori launchpad.
For now lets open batch request in the new tab & replace
$batch?sap-client=200
With GET request from the Payload tab
C_InspLotMltplRsltRec?sap-client=200&$skip=0&$top=20
The URL will look like
/sap/opu/odata/sap/QM_MLTPLRR_SRV/C_InspLotMltplRsltRec?sap-client=200&$skip=0&$top=20
Let’s try to analyze it the result
More or less readable, but probably XML is not the easiest format to understand the actual data.
Now just &$format=json to the end of the URL
Is it a little easier than XML? If not then just install Chrome’s or Edge's JSON Formatter plugin first
And now when we see the data from backend we can return to the agenda:
If we go back the URL
/sap/opu/odata/sap/QM_MLTPLRR_SRV/C_InspLotMltplRsltRec?sap-client=200&$skip=0&$top=20&$format=json
the most astute one already guess that C_InspLotMltplRsltRec is a CDS. But let’s check it. If we try to open QM_MLTPLRR in Eclipse (Ctrl+Shigt+A)
Yes it is CDS reference based SEGW project.
For RAP & CDS referenced projects we can add can extend CDS by SQL
Usually it’s necessary to some kind of texts using system language ($session.system_language). Just don’t forget to ZZ* prefix for custom fields 😊 for safety reason.
But what if SQL is not enough and we have to use ABAP for newly created fields?
In the method we need only fill ZZ_HasDiff field.
The definition of C_InspLotMltplRsltRec will already contain newly created custom field
Let's check result in the browser
The new field is ready. How to display it in sap.m.Table?
It's time to create Fiori Adaptation Project
But before that we have to install 1 particular generator VS Code
press Ctrl+Shift+P & type explore ...
After installation just press Ctrl+Shift+P again & type Adaptation ...
The Namespace is always start with customer.* & is not necessary to start Project with Z*. But for clarity is better to start with Z*. In ABAP terminology the Namespace is kind of enhancement for a Fiori application. And developer can create several of namespaces that do not overlap with each other.
In the next just type Fiori app & press Finish
In NPM scripts just launch start-editor
The good thing is that we easily add new Fragments in editor
The bad news is that for most of the tree we can't add fragments because someone forgot to name the XML view.
That’s why they are greyed in the tree.
What we can do?
The structure of *.change files is pretty simple. And we can use the 2nd approach. Just use it from another project or view & adjust some of the fields.
The most important one is a selector. By default Fiori adaption editor uses global names(idIsLocal: true)
Let’s start from the simple button in the toolbar
Selectors with “__xmlview1--” do not look like firm, but they are work
\webapp\changes\fragments\fragToolbar.fragment.xml
<!-- Use stable and unique IDs!-->
<core:FragmentDefinition xmlns:core='sap.ui.core' xmlns='sap.m'>
<Button id="custBtWriteDiff" text="Overwrite difference"
enabled="false"
press=".extension.customer.zqmu0001.contPage.onBtWriteDiff"/>
</core:FragmentDefinition>
Controller extension is not created yet but the new button is visible now
Now we are ready to a new column & a cell to our project
New sap.m.Column
<!-- Use stable and unique IDs!-->
<core:FragmentDefinition xmlns:core='sap.ui.core' xmlns='sap.m'>
<Column id="custDiffColumn">
<Text id="custDiffText" text="Difference" />
</Column>
</core:FragmentDefinition>
& new cell
<!-- Use stable and unique IDs!-->
<core:FragmentDefinition xmlns:core='sap.ui.core' xmlns='sap.m'>
<ObjectStatus
id="custDiffValue"
class="sapUiSmallMarginBottom"
icon ="{= ${ZZ_HasDiff} === 'I' ? 'sap-icon://message-success': ${ZZ_HasDiff} === 'W' ? '' : 'sap-icon://cancel' }"
active="false"/>
</core:FragmentDefinition>
But if we check $batch request now we still cannot ZZ_HasDiff in it.
Why? Because they statically requested in the view itself.
Let’s add new field via Controller extension
In adaptation mode just right click on desired view & select Extend With Controller
In UI5 inspector we can find inspectionLotSmartTable (sap.ui.comp.smarttable.SmartTable)
And we need to change its property requestAtLeastFields
Most of the code can be written without extra JS knowledge. Just find control in UI5 Inspector & find specific event in https://sapui5.hana.ondemand.com/#/api
const mainTable = this.getView().byId('inspectionLotTable')
// Set enable button 'Write Difference'
mainTable.attachSelectionChange(() => {
const button = this.getView().byId('customer.zqmu0001.custBtWriteDiff')
const oSelectedInspectionLots = mainTable.getSelectedItems();
button.setEnabled(oSelectedInspectionLots.length > 0 && mainTable.getMode() === sap.m.ListMode.MultiSelect)
})
Very often we need to implement some actions after DB manipulation. To set a “handler” to CRUD operation 1st of all we have to access parent controller this.base & then call following sequence getOwnerComponent().getModel() to get a model.
// Refresh main table when characteristics are saved
this.base.getNewODataModel().attachRequestCompleted(function (oEvent) {
if (oEvent.getParameter('url') === 'C_InspResultMltplRsltRec' &&
oEvent.getParameter('method') === 'POST' &&
oEvent.getParameter('success'))
mainTable.getBinding("items").refresh();
})
where getNewODataModel is declared in BaseController-dbg.js
getNewODataModel: function () {
return this.getOwnerComponent().getModel();
}
In event parameters all necessary information is passed to handler. Just write
console.log(oEvent.mParameters);
to see them all.
UI5 Inspector helps with XML view a lot. But how to enhance JS code?
Just press F12 in Chrome again & put break-points in the Source tab & try to understand existing code. Let’s assume we spent some time & found out some necessary JS code in controller or customControl folders.
But can we change the behavior of class without modification of source code? Yes we can!
For instance assume that in \QM_MLTPL_RR_S1\customControl\CodeGroupInput-dbg.js we have to “redefine” onConfirm method. How to do it?
/*
* Copyright (C) 2009-2022 SAP SE or an SAP affiliate company. All rights reserved.
*/
//for Template8
sap.ui.define(["sap/m/Input",
…
"i2d/qm/inspmltpl/resultsrecords1/util/UpdateSidePanel",
"i2d/qm/inspmltpl/resultsrecords1/model/formatter"
], function (Input, …, UpdateSidePanel, formatter) {
"use strict";
return Input.extend("i2d.qm.inspmltpl.resultsrecords1.customcontrol.CodeGroupInput", {
onConfirm: function (oEvent) {
The 1st step is to import class to our code.
Then override old behavior using prototype
// When F4 value is selected
CodeGroupInput.prototype.onConfirm = function (oEvent) {
var aContexts = oEvent.getParameter("selectedContexts");
...
}
we can call super method by
CodeGroupInput.prototype.onConfirm.apply(this, arguments);
& even rewrite it completely if we want.
In next article let’s discus deploying Adaptation project to SAP & loading previous version & creating tile for our “enhancement”.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
9 | |
7 | |
6 | |
6 | |
5 | |
5 | |
4 | |
4 | |
4 | |
3 |