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

[SAPUI5] Parse error message

If the error response is type json:

        oModel.callFunction("/myFunction", {
          method: "GET",
          urlParameters: {
            ID: myID,
          },
          success: oData => console.log(oData),
          error: oError => MessageBox.error(JSON.parse(oError.responseText).error.message.value, { title: "An error occurred" })
        });

If the error response is coming from a Gateway and has an XML body (link):

 MessageBox.error(jQuery.parseXML(oError.response.body).querySelector("message").textContent)

[SAPUI5] Call function of another controller using EventBus

https://sapui5.hana.ondemand.com/#/api/sap.ui.core.EventBus%23overview

In the receiving controller you need to subscribe your eventId and function you want to call from the second controller:

// Attaches an event handler to the event with the given identifier on the given event channel            
this.getOwnerComponent().getEventBus().subscribe("Default", "myEventId", () => {
    this._myFunctionIWantToCall();
});

The sending controller has to publish the event to trigger the function call:

// Fires an event using the specified settings and notifies all attached event handlers.
this.getOwnerComponent().getEventBus().publish("Default", "myEventId", {});

[SAPUI5] Get and set properties of a binded model and submit changes

Get:

const oModel = this.getView().getModel()
const sPath = this.getView().getBindingContext().sPath
const sID = oModel.getProperty(sPath+"/ID")

Set:

const newID = "12345"
oModel.setProperty(sPath+"/ID", newID)

When using the set property function, you can now submit your changes this way:

        // First check if there are any changes    
        if (!oModel.hasPendingChanges()) {
           MessageToast.show("Nothing to do!")
           return
        }
        
        // Now submit your changes
        oModel.submitChanges({
          success: () => MessageToast.show("Success!"),
          error: (err) => alert(err)
        })

This way is much more comfortable, than using oModel.update().

[SAPUI5] Filter on Model read

this.getModel().read("/Object", {
                filters: [
                    new Filter({
                        path: "firstName",
                        operator: FilterOperator.EQ,
                        value1: "Max"
                    }),
                    new Filter({
                        path: "lastName",
                        operator: FilterOperator.EQ,
                        value1: "Mustermann"
                    })
                ],
                success: oData => { },
                error: err => { }
});

[SAPUI5] Binding with filter on XML View

https://sapui5.hana.ondemand.com/sdk/#/topic/5338bd1f9afb45fb8b2af957c3530e8f.html

There are two ways to use a filter.

Option 1:

items="{
				path: '/myItems',
				parameters : {
				  $filter : 'itemName eq \'myItemName\'',
				  $orderby : 'createdAt desc'
				},
}">

Option 2:

items="{
				path: '/myItems',
				parameters : {
				  $orderby : 'createdAt desc'
				},
				filters : {                                     
				  path : 'itemName ',
				  operator : 'EQ',
				  value1 : 'myItemName'
				},
}">

[SAPUI5] Toogle Dark mode from Shell Header

There are several different types of buttons you can add to the Shell Header: https://sapui5.hana.ondemand.com/sdk/#/api/sap.ushell.renderers.fiori2.Renderer%23methods/Summary
For my test I choose the “addHeaderEndItem” Button. Add the fowlloing logic in the Component.js file to create the button and the logic for switching the theme:

		_addHeaderButton: function () {
			const oRenderer = sap.ushell.Container.getRenderer("fiori2");
			oRenderer.addHeaderEndItem("sap.ushell.ui.shell.ShellHeadItem", {
				id: "toogleTheme",
				icon: "sap-icon://circle-task-2",
				visible: "{device>/orientation/landscape}",
				tooltip: "Switch Theme",
				press: (oEvent) => {
					const toogleButton = oEvent.getSource();
					if (toogleButton.getIcon() === "sap-icon://circle-task-2") {
						sap.ui.getCore().applyTheme("sap_fiori_3_dark");
						toogleButton.setIcon("sap-icon://circle-task");
					} else {
						sap.ui.getCore().applyTheme("sap_fiori_3");
						toogleButton.setIcon("sap-icon://circle-task-2");
					}
				}
			}, true);
		},

Afterwars you need call the method in the init() function of the component. No reload the app and you will find the new button in the top right corner. Pressing will switch the theme to dark or back to light theme.

[SAPUI5] Message Box

https://experience.sap.com/fiori-design-web/message-box/
https://sapui5.hana.ondemand.com/#/entity/sap.m.MessageBox
https://sapui5.hana.ondemand.com/#/api/sap.m.MessageBox

			onRemoveItem: function (oEvent) {
				const sPath = oEvent.getSource().getParent().getBindingContext().getPath()
				const oModel = this.getView().getModel()
				MessageBox.confirm(
					this.getModel("i18n").getProperty("MessageBoxText"), 
					{
						actions: [MessageBox.Action.YES, MessageBox.Action.NO],
						emphasizedAction: MessageBox.Action.YES,
						onClose: sAnswer => {
							if (sAnswer === MessageBox.Action.YES) oModel.remove(sPath)
						}
					}
				)
			},

[SAPUI5] UI5 Web Components

https://blogs.sap.com/2020/12/21/using-ui5-web-components/

“With UI5 Web Components, developers can build the core logic of the application using these popular web frameworks, while using UI5 Web Components as the visual elements (controls).

Each of these web frameworks have different ways of handling data layer, persistence, binding, and integration with APIs, etc. but the nice thing about web components is that is integrates easily, regardless of the framework.”

[OpenUI5] SAP Fiori elements add-on for OpenUI5 using an OData V4 service

Recently I found this blog post about the new SAP Fiori elements add-on for OpenUI5.
https://blogs.sap.com/2020/12/21/now-available-sap-fiori-elements-add-on-for-openui5/
It includes a little exercise to try it out for yourself. I wrote down all steps I had to make on my Linux Mint 20 installation.
These two links also helped me a lot.
https://github.com/sap-samples/cloud-cap-samples
https://cap.cloud.sap/docs/get-started/

Prerequisites (Node.js, Visual Studio Code, SAP Fiori tools, Git)

curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash -
sudo apt-get install -y nodejs
node --version
npm -v 

Change npm’s default directory to prevent permission errors.
https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally

mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
mkdir ~/.npm-global/lib
#add the following line to your .bashrc or .profile or .zshrc
export PATH=~/.npm-global/bin:$PATH

Step 1: Provide an OData V4 service

git clone https://github.com/sap-samples/cloud-cap-samples remote-odata-service
cd remote-odata-service
npm i 
npm i -g @sap/cds-dk
cds watch fiori

Step 2: Generate a SAP Fiori elements List Report Object Page (LROP) app with Fiori tools

1. Open VSC, press Ctrl + P and search for > Fiori: Open Application Generator

2. Choose SAP Fiori elements application
In my case there was no default generator, so first I had to install it.

npm install -g @sap/generator-fiori-elements@latest

This can also be done directly in VSC.

3. Select List Report Object Page
4. Select Connect to an OData Service as Data source and enter as URL http://localhost:4004/browse
5. Choose Books as the Main entity and texts as Navigation entity
6. Complete the mandatory information module name (e.g. bookshop) and Project folder path for storing your app. Of course, you can also fill in the optional information.

Step 3: Make changes in package.json and ui5.yaml required for using OpenUI5

package.json

{
	"name": "fiorielements_openui5",
	"version": "0.0.1",
	"private": true,
	"sapux": true,
	"description": "A Fiori application.",
	"keywords": [
		"ui5",
		"openui5",
		"sapui5"
	],
	"main": "webapp/index.html",
	"scripts": {
		"start": "fiori run --open index.html",
		"start-local": "fiori run --config ./ui5-local.yaml --open index.html",
		"build": "ui5 build -a --clean-dest --include-task=generateManifestBundle generateCachebusterInfo",
		"deploy": "fiori add deploy-config"
	},
	"devDependencies": {
		"@sap/ux-specification": "latest",
		"@sap/ux-ui5-tooling": "1",
		"@ui5/cli": "2.5.0",
		"@ui5/fs": "2.0.1",
		"@ui5/logger": "2.0.0"
	},
	"ui5": {
		"dependencies": [
			"@sap/ux-ui5-tooling",
			"@sap/open.fe"
		]
	},
	"dependencies": {
		"@sap/open.fe": "1.85.0"
	}
}

ui5.yaml

specVersion: '2.2'
metadata:
  name: 'fiorielements_openui5'
type: application
framework:  
  name: OpenUI5  
  version: "1.85.0"  
  libraries:   
  - name: sap.m  
  - name: sap.ui.core  
  - name: sap.uxap
  - name: themelib_sap_fiori_3
server:
  customMiddleware:
  - name: fiori-tools-proxy
    afterMiddleware: compression
    configuration:
      ignoreCertError: false # If set to true, certificate errors will be ignored. E.g. self-signed certificates will be accepted
      backend:
      - path: /browse
        url: http://localhost:4004
  - name: fiori-tools-appreload
    afterMiddleware: compression
    configuration:
     port: 35729
     path: webapp

Step 4: Run the V4 application

cd ~/projects/fiorielements_openui5
npm i
npm start

Now http://localhost:8080/index.html should be opened in your browser.
“Note: Clicking on the Go button in List Report application might request  user and password. Please enter user alice, no password.”
Finally I got my list items.

[SAPUI5] Busy Dialog

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"));
			}
	});
},