Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[SAPUI5] Busy Dialog

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
onInit: function () {
    this._oModel = this.getOwnerComponent().getModel();
},
 
onButtonPress: function (oEvent) {
    //get Data
    var sPath = oEvent.getSource().getBindingContext().sPath;
    var oData = this.getView().getModel().getObject(sPath);
    var that = this;
 
    //busy on
    this._busyDialog = new sap.m.BusyDialog({});
    this._busyDialog.open();
 
    //create
    this._oModel.create("/DataSet", oData, {
            success: function (oData) {
                    that._busyDialog.close();
                    sap.m.MessageToast.show(that.getResourceBundle().getText("ok"));
            },
            error: function (oError) {
                    that._busyDialog.close();
                    sap.m.MessageToast.show(that.getResourceBundle().getText("nok"));
            }
    });
},

[SAPUI5] MyInbox: Integration of Detail View – EmbedIntoDetail

https://launchpad.support.sap.com/#/notes/2305401 (App to App Navigation CookBook.pdf)

https://blogs.sap.com/2020/07/31/fiori-my-inbox-integration-of-custom-detail-page/

Target:

Go to /n/ui2/fpld_cust and define a second target for your App, i.e. approve.

The approve target needs the “emdedIntoDetails” parameter:

SWFVISU:

Add the new target for your WF Task. Here you have access to all attributes of your Workitem-Container. Pass all your mandatory fields you’ve defined in your oData Entity.

Some examples: https://blogs.sap.com/2016/05/31/my-inbox-open-task-swfvisu-configuration/

If your missing some parameters, just add them in your Workitem Task and pass the values directly into it right from your Workflow Container. This looks much better.

Manifest:

Add a route to navigate via Inbox. The pattern has to match your inbox url.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
"routes": [
    {
        "pattern": "",
        "name": "master",
        "target": "master"
    },
    {
        "pattern": "DataSet/{Pernr},{Datum},{Infty}",
        "name": "object",
        "target": [
            "master",
            "object"
        ]
    },
    {
        "pattern": "detail/LOCAL_INBOX/{wfInstanceId}/{taskPath}",
        "name": "wfobject",
        "target": "object"
    }

Detail.Controller:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
onInit: function () {
        // Model used to manipulate control states. The chosen values make sure,
        // detail page is busy indication immediately so there is no break in
        // between the busy indication for loading the view's meta data
        var oViewModel = new JSONModel({
            busy: false,
            delay: 0
        });
 
        this.getRouter().getRoute("object").attachPatternMatched(this._onObjectMatched, this);
 
        //My Inbox Integration
        this.getRouter().getRoute("wfobject").attachPatternMatched(this._onWFObjectMatched, this);
 
        this.setModel(oViewModel, "detailView");
 
        this.getOwnerComponent().getModel().metadataLoaded().then(this._onMetadataLoaded.bind(this));
 
    },
 
 
    _onWFObjectMatched: function (oEvent) {
        this.getModel("appView").setProperty("/layout", "MidColumnFullScreen");
        var compData = this.getOwnerComponent().getComponentData();
 
        if (compData && compData.startupParameters && compData.startupParameters.PERNR && Array.isArray(compData.startupParameters.PERNR) &&
            compData.startupParameters.PERNR[0]) {
 
            var sPernr = compData.startupParameters.PERNR[0];
            var sDatum = compData.startupParameters.DATUM[0];
            var sInfty = compData.startupParameters.INFTY[0];
 
            this.byId("detailPage").addStyleClass("myInboxPage");
 
            this.getModel().metadataLoaded().then(function () {
                var sObjectPath = this.getModel().createKey("/DataSet", {
                    Pernr: sPernr,
                    Datum: sDatum,
                                      Infty: sInfty
                });
                this._bindView(sObjectPath);
 
            }.bind(this));
        }
    },

[SAPUI5] uncheck checkbox if another one is selected

XML

1
2
<Checkbox id="Checkbox1" selected="{ path:'oModel>CB1' }" select="handleOrderSelected"></Checkbox>  
<Checkbox id="Checkbox2" selected="{ path:'oModel>CB2' }" select="handleRejectSelected"></Checkbox>

controller.js

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
handleOrderSelected: function (oEvent) {
    //Wenn Checkbox1 selektiert, setze Checkbox2 auf false.
    var bSelected = oEvent.getParameter("selected");
    if (bSelected) {
        var bindingContext = oEvent.getSource().getBindingContext("oModel");
        this.oModelTemplate.setProperty("CB2", "", bindingContext, false);
    }
},
 
handleRejectSelected: function (oEvent) {
    //Wenn Checkbox2 selektiert, setze Checkbox1 auf false.
    var bSelected = oEvent.getParameter("selected");
    if (bSelected) {
        var bindingContext = oEvent.getSource().getBindingContext("oModel");
        this.oModelTemplate.setProperty("CB1", "", bindingContext, false);
    }
}

[SAPUI5] Copy Table Row

Button für das Kopieren einer Zeile hinzufügen.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<Table id="itemsTable" items="{oModel>/ITEMS}">
<columns>
      <Column id="splitColumn" hAlign="Center" demandPopin="false">
            <Text text="{i18n>SPLIT}"/>
      </Column>
</columns>
<items>
      <ColumnListItem>
            <cells>
                  <Button press="onSplitPressed" id="SPLIT_ROW" icon="{= ${oModel>CUSTOM_ITEM} === true ? 'sap-icon://delete' : 'sap-icon://add'}"/>
            </cells>
      </ColumnListItem>
</items>
</Table>

Nur neu hinzugefügte Zeilen sollen auch wieder gelöscht werden dürfen, daher werden manuell hinzugefügte Zeilen markiert mit CUSTOM_ITEM = True;
Via Expression Binding wird dann das erforderliche Icon bestimmt.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
onSplitPressed: function (oEvent) {
        var oContext = oEvent.getSource().getBindingContext("oModel");
        var path = oContext.getPath();
        var oModel = oContext.getModel();
        var oItems = oModel.getProperty("/ITEMS");
        var index = path.substr(path.length - 1);
 
        //selektiertes Item lesen
        var oItem = oModel.getProperty(path);
 
        //was soll passieren? Zeile hinzufügen oder entfernen?
        if (oItem.CUSTOM_ITEM !== true) {
 
            //Neues Item anlegen
            var oNewItem = JSON.parse(JSON.stringify(oItem));
            //Markiere neue Zeile, da nur diese auch wieder gelöscht werden darf
            oNewItem.CUSTOM_ITEM = true;
            // +1 weil Zeile soll ja nach der Aktuellen einfügt werden
            index++;
            oItems.splice(index, 0, oNewItem);
 
        } else {
            // Item löschen
            oItems.splice(index, 1);
        }
 
        oModel.setProperty("/ITEMS", oItems);
    },

[Fiori] Debug deployed Fiori App

When opening the Dev-Tools for a deployed Fiori App, it will look like this:

You won’t see any controller.js to debug.
What to do? Close the Debugger-Tools and hit CTRL+ALT+SHIFT+P to open the Technical Information Dialog

Check the Checkbox (or choose a specific controller) and reload the app.

It reloads with a new URL parameter and if you open the Dev-Tools, you will now see the controller.js.

Other options to debug or at least to collect some information about your app are the UI5 Diagnostics (hit CTRL+ALT+SHIFT+S) and the UI5 Inspector which is a Brower Addon.

[SAPUI5] Formatting numbers

https://experience.sap.com/fiori-design-web/formatting-numbers/#usage
https://sapui5.netweaver.ondemand.com/sdk/#/topic/91f3145e6f4d1014b6dd926db0e91070
a few examples: https://github.com/brooklynb7/HTML5/blob/master/sapui5-dist-static/test-resources/sap/ca/ui/demokit/explored/views/type/number.view.xml

1
2
3
4
<ObjectListItem
title="{income>Month}"
number="{ model : 'income', path : 'Cost', type: 'sap.ui.model.type.Integer', formatOptions: {groupingEnabled: true} }"
numberUnit="EUR" />

[SAPUI5] Deploying the ui5 sample app on debian

I’m deploying the openui5-sample-app to a Linux Container running Debian Buster. First update the packages and install Node.js.

1
2
3
4
5
apt update && apt upgrade -y
apt install curl -y
curl -sL https://deb.nodesource.com/setup_12.x | bash -
apt install nodejs -y
nodejs --version

Install PM2 (process manager to manage Node.js applications) and the UI5 Tooling

1
2
npm install pm2 -g
npm install --global @ui5/cli

Now clone the openui5-sample-app and build it

1
2
3
4
5
apt install git
git clone https://github.com/SAP/openui5-sample-app.git
cd openui5-sample-app/
ui5 build -a
cd ..

Run your project on port 8000. With “startup” it will automatically create a systemd script.

1
2
3
4
5
pm2 serve openui5-sample-app/dist/ 8000
pm2 startup
pm2 save
systemctl start pm2-root
systemctl status pm2-root

[SAPUI5] local ui5 development

1. Install node.js

2. Install UI5 Tooling

1
npm install --global @ui5/cli

3. Install Easy UI5 Generator, create a project and run it on your localhost

1
2
3
4
npm install -g yo generator-easy-ui5
yo easy-ui5
cd &lt;your project name>
npm start

4. Set up a Github project and do your initial push

1
2
3
4
git add .
git commit -m "Initial commit"
git push origin master

5. Install your favorite Editor, e.g. Visual Studio Code or Atom, and open your project to edit it