SAPUI5 Advanced

Best Practice Übungen

Übung 1: Generieren einer UI5 Freestyle Applikation

Übung 2: Spalten mit Buttons ergänzen

Übung 3: Base Controller

Übung 4: Backend Calls

Übung 5: Errorhandling

Übung 6: OData Messages optimiert

Übung 7: XML View verbessern

Brandeis Consulting & Cadao

Generell zu den Übungen

  • Die Übungen sind so vorbereitet, dass eigentlich durch schlichtes Copy/Paste alles funktioineren sollte.
  • Trotzdem rate ich Euch:
    • Versucht die Beispielcodings zu verstehen
    • Wenn Zeit ist, bitte manuell coden
    • Copy/Paste nur wenn die Zeit eng wird oder man den Fehler nicht findet
Brandeis Consulting & Cadao

Best Practice Übung 1: UI5 Freestyle Anwendung

Damit wir im Laufe des Workshops weitere Übungen machen können, generieren wir uns erneut eine Freestyle Anwendung und machen ein paar Anpassungen.

  • Aufgabe 1.1 Generieren der UI5 Freestyle Anwendung
  • Aufgabe 1.2 Erste View Anpassungen
  • Aufgabe 1.3 UI5 Tabelle hinzufügen
  • Aufgabe 1.4 Weitere Spalten hinzufügen
Brandeis Consulting & Cadao

Best Practice Übung 1: Aufgabe 1.1 - Generieren der UI5 Freestyle Anwendung

In dieser Übung wird eine Freestyle App mit dem Template Generator angelegt und wir werden verschiedene Anpassungen vornehmen.

  • Starten Template Wizard mit STRG + SHIFT + P
  • Generator SAP Fiori application auswählen
  • Template Basic auswählen
  • Data Source, System (K1X) entsprechend auswählen
  • Service ZDB_C_TRAVEL_PROC_M_SB_V2
  • Module: demotravel##
  • Application namespace: de.ui5ws.demos
  • ACHTUNG auf den Project Folder: /home/user/projects (Vorschlag ändern!!!!!)
  • Keine Deployment Config, kein FLP, kein Advanced Options
  • Starten -> Warten -> Testen
    • Popup "Add project ot workspace" auswählen
Brandeis Consulting & Cadao

Best Practice Übung 1: Aufgabe 1.2 - Erste View Anpassungen

Jetzt machen wir erste View Anpassungen und machen aus der Seite eine dynamisch Page.

Um die dynamic Page verwenden zu können, benötigen wir sap.f:

xmlns:f="sap.f"

Und dann können wir im View die dynamic Page aufnehmen:

<f:DynamicPage id="dynamicPageId">
    <f:header>
        <f:DynamicPageHeader pinnable="true">
            <Text text="Test Header"/>
        </f:DynamicPageHeader>
    </f:header>
    <f:content >
        <Text text="Test Content"/>
    </f:content>
</f:DynamicPage>

Fragestellungen

  • Ist nun eine Dynamic Page (Header und Content getrennt) sichtbar?
Brandeis Consulting & Cadao

Best Practice Übung 1: Aufgabe 1.3 - Tabelle hinzufügen

Wir fügen nun eine sap.ui.table Tabelle hinzu. Für diese Übungen verzichten wir auf eine Filter und zeigen die Daten sofort an.

XML View

xmlns="sap.ui.table"

Und im View ersetzen wir den inhalt von <f:content>:

XML View

<Table rows="{/Travel}"
       visibleRowCount="15"
       selectionMode="MultiToggle"
       paste="onPaste"
       ariaLabelledBy="title">
        <extension>
            <m:OverflowToolbar style="Clear">
                <m:Title id="idTitle" text="{i18n>tableTitle}"/>
            </m:OverflowToolbar>
        </extension>

XML View Fortsetzung

        <columns>
            <Column>
                <m:Label text="Travel ID" />
                <template>
                    <m:Text text="{TravelID}" />
                </template>
            </Column>
        </columns>
</Table> 
Brandeis Consulting & Cadao

Best Practice Übung 1: Aufgabe 1.4 - Weitere Spalten hinzufügen

Als nächstes brauchen wir noch weitere Spalten. Bitte fügen Sie folgende Spalten nach gleichem Muster wie in der vorigen Übung hinzu:

  • Agency Name, {AgencyName}
  • Customer Name, {CustomerName}
  • Total Price, {TotalPrice}
  • Status, {OverallStatus}
  • Status Text, {OverallStatusText}

Fragestellungen

  • Sind nun auch die weiteren Spalten sichtbar?
Brandeis Consulting & Cadao

Best Practice Übung 2: Buttons zum freigeben / ablehnen

In dieser Übung werden wir 3 Spalten mit Buttons zum freigeben, ablehnen oder zurücksetzen aufnehmen.

  • Aufgabe 2.1 Button Spalten hinzufügen
  • Aufgabe 2.2 Button Text aus i18n
  • Aufgabe 2.3 Button mit Expression Binding aktivieren/deaktivieren
  • Aufgabe 2.4 Expression Binding über Formatter
  • Aufgabe 2.5 Spalten Labels mit Metadata Binding
  • Aufgabe 2.6 Button Text aus i18n - nun mit Placeholder
Brandeis Consulting & Cadao

Best Practice Übung 2: Aufgabe 2.1 - Button Spalten hinzufügen

In der Anwendung wollen wir in jeder Zeile 3 Buttons haben. Zum "Approven", "Rejecten" und "Reseten". Deshalb müssen wir jetzt 3 weitere Spalten hinzufügen. Jetzt jedoch vom Typ Button.

<m:Button width="100%"
          type="Accept"
          text="Accept" 
          press="onPressAccept" />

Und noch zwei weitere Buttons:

  • type="Reject", text="Reject", press="onPressReject"
  • text="Reset", press="onPressReset"

Fragestellungen

  • Sind nun auch alle 3 Buttons sichtbar?
Brandeis Consulting & Cadao

Best Practice Übung 2: Aufgabe 2.2 - Button Text aus i18n

Wir wollen nun die Texte der Buttons aus der i18n lesen. Dafür legen wir 3 Texte an. Um eine bessere Lesbarkeit zu erreichen, können wir auch "." im Key verwenden:

i18n.properties

mainView.buttonTextAccept=Accept 
mainView.buttonTextReject=Reject 
mainView.buttonTextReset=Reset

In den Buttons muss natürlich auch der "harte" Text bei allen Buttons getauscht werden:

XML View

... {i18n>mainView.buttonTextAccept} ...

Fragestellungen

  • Kommen nun alle Texte wie gewünscht aus der i18n?
Brandeis Consulting & Cadao

Best Practice Übung 2: Aufgabe 2.3 - Button mit Expression Binding

Die Buttons sollen nur abhängig vom Feld OverallStatus aktiv sein. Folgende Status sind möglich:

  • O Open
  • X Rejected
  • A Approved

Über ein Expression Binding sollen die beiden Buttons zum Freigeben oder Ablehnen nur aktiv sein, wenn der OverallStatus O ist. Der Zurücksetzen Button soll nur aktiv sein, wenn der Status ungleich O ist.

XML View - Beispiel

... enabled="{= ${OverallStatus} === 'O' ? true : false }" ...

Fragestellungen

  • Sind die Buttons nun abhängig vom Status aktiv / inaktiv
Brandeis Consulting & Cadao

Best Practics Übung 2: Aufgabe 2.4 - Expression Binding über Formatter

Unsere eben angelegte Expression ist leicht lesbar. Trotzdem haben wir bei Approve und Reject die gleiche Expression. Dies wollen wir ändern und die Expression mit einem Custom Formatter im Controller setzen.

XML View

... enabled="{ path:'OverallStatus', formatter:'.formatterAcceptRejectButton' }" ...

Controller

formatterAcceptRejectButton: function(OverallStatus) {
    return OverallStatus === 'O' ? true : false;
}

Fragestellungen

  • Sind die Buttons weiterhin abhängig vom Status aktiv / inaktiv?
Brandeis Consulting & Cadao

Best Practice Übung 2: Aufgabe 2.5 - Spalten Labels mit Metadata Binding

Informationen aus den Metadaten können auch mit Binding verwendet werden. Beispielsweise wollen wir die Spaltenüberschrift aus den Metadaten verwenden.

<m:Label text="{/#Travel/TravelID/@sap:label}" />
  • Wer will kann das bei allen Spalten machen
  • Beispielsweise könnten hier auch Feldlängen verwendet werden

Fragestellungen

  • Wir die Spaltenüberschrift jetzt von den Metadaten gezogen
Brandeis Consulting & Cadao

Best Practice Übung 2: Aufgabe 2.6 - Button Text aus i18n - nun mit Placeholder

In dieser Aufgabe wollen wir nun die Platzhaler bei den i18n Texten verwenden. Konkret wollen wir im Buttontext bei Accept und Reject auch den Betrag & Währung aufnehmen.

Zuerst müssen wir zwei Platzhalter (Betrag und Währung) in den Language Files aufnehmen

i18n.properties

mainView.buttonTextAccept=Accept {0} {1}
mainView.buttonTextReject=Reject {0} {1}

XML View

<m:Button  xmlns:core="sap.ui.core"
    ... 
    core:require="{ formatMessage: 'sap/base/strings/formatMessage' }"
    ...
    text="{ parts: [ 'i18n>mainView.buttonTextAccept',
                     'TotalPrice',
                     'CurrencyCode' ],
            formatter: 'formatMessage' }" 
    ... />

Fragestellungen

  • Werden nun in den Buttons auch der Betrag und die Währung ausgegeben
Brandeis Consulting & Cadao

Best Practice Übung 3: Base Controller

Der Controller wird länger und länger und sollten wir einen weiteren View benötigen kann es durchaus sein, dass wir redundante Methoden benötigen. Der in der vorigen Übung angelegte Formatter könnte so ein Fall sein.

In dieser Übung wollen wir nun einen Base Controller ins Spiel bringen und den in der vorigen Übung angelegten Formatter in diesen neuen Base Controller verschieben.

  • Aufgabe 3.1 Neuen Base Controller anlegen
  • Aufgabe 3.2 Base Controller im View Controller verwenden
  • Aufgabe 3.3 Formatter in den Base Conroller verschieben
Brandeis Consulting & Cadao

Best Practice Übung 3: Aufgabe 3.1 - Neuen Base Controller anlegen

Der neue Controller BaseController.js ist im Verzeichnis webapp/controller anzulegen. Vorerst bleibt er noch komplett "leer"

BaseController.js

sap.ui.define([
    "sap/ui/core/mvc/Controller"
  ], function(Controller) {
  
    "use strict";
    return Controller.extend("db.com.dbadvanced.controller.BaseController", {
  
    });

  });

Fragestellungen

  • Diese Aufgabe sollte keine Auswirkung auf die Anwendung haben
Brandeis Consulting & Cadao

Best Practice Übung 3: Aufgabe 3.2 - View Controller anpassen

Im View Controller ist nun Standard Controller durch den neu erstellten Controller auszutauschen.

View Controller

sap.ui.define([
    "db/com/dbadvanced/controller/BaseController",
...

Fragestellungen

  • Diese Aufgabe sollte immer noch keine Auswirkung auf die Anwendung haben
Brandeis Consulting & Cadao

Best Practice Übung 3: Aufgabe 3.3 - Formatter verschieben

Nun können wir z.B. die Custom Formatter Methode in den Base Controller verschieben.

BaseController.js

sap.ui.define([
    "sap/ui/core/mvc/Controller"
  ], function(Controller) {
  
    "use strict";
    return Controller.extend("db.com.dbadvanced.controller.BaseController", {
  
        formatterAcceptRejectButton: function(OverallStatus) {
            return OverallStatus === 'O' ? true : false;
        }

    });

  });

Fragestellungen

  • Diese Aufgabe sollte weiterhin noch keine Auswirkung auf die Anwendung haben
  • Aber jetzt können wir zentral steuern, wann die Buttons aktiv sein sollen
Brandeis Consulting & Cadao

Best Practice Übung 4: Backend Calls

Jetzt geht es darum, dass wir ein paar Backend Calls (OData Calls) implementieren.

  • Aufgabe 4.1 Button Press Events implementieren
  • Aufgabe 4.2 Success und Error
  • Aufgabe 4.3 Einfaches Errorhandling
Brandeis Consulting & Cadao

Best Practice Übung 4: Aufgabe 4.1 - Button Press Events implementieren

Bis jetzt machen die Buttons noch nichts. Mit dieser Aufgabe implementieren wir den Backend Call ins SAP.

Dafür müssen wir einfach die in den Button hinterlegten Press Methoden implemenieren.

Beispiel onPressAccept

onPressAccept: function ( oEvent ) {
    var params = {};
    params.TravelID = this.oModel.getProperty( oEvent.getSource().getParent().getBindingContext().getPath() + '/TravelID' );;

    this.oModel.callFunction("/acceptTravel", { method: "POST",     
                                                urlParameters: params,	
                                                success: this.onSuccessCallFunction.bind(this), 
                                                error: this.onErrorCallFunction.bind(this)
                                                });
}
  • Nicht vergessenauf onPressReject und onPressReset.
  • Die dazugehürigen OData Funktionen sind rejectTravel und resetTravel

Fragestellungen

  • Wird nun beim Drücken der Buttons das Backend Event "gefeuert"?
Brandeis Consulting & Cadao

Best Practice Übung 4: Aufgabe 4.2 - Success und Error

Später werden wir uns noch genauer mit dem Success / Error beschäftigen. An der Stelle implementieren wir einfach einmal zwei "fast" leere Methoden. Für Accept, Reject und Reset.

Beispiel onSuccessCallFunction und onErrorCallFunction

onSuccessCallFunction: function ( oResult ){
   MessageToast.show( 'erfolgreich' );
},
onErrorCallFunction: function ( oResult ){
   MessageToast.show( 'fehlerhaft' );
},

Nicht vergessen, damit MessageToast verwendet werden kann, muss es oben im define aufgenommen werden:

sap.ui.define([
	"sap/ui/core/mvc/Controller",
	"sap/m/MessageToast"
],
	...
	function (Controller, MessageToast ) {

Fragestellungen

  • Was passiert jetzt beim Drücken der Buttons?
Brandeis Consulting & Cadao

Best Practice Übung 5: OData Fehlermeldung (einfach) ausgeben

Versuchen Sie mal eine freigegeben oder abgelehnte Reise welche mehr als 5000 kostet mit "Reset" zurückzusetzen. Es sollte nichts passieren - da im Backend ein Fehler ausgelöst wird. Und diesen Fehler wollen wir mit dieser Aufgabe anzeigen. OData Messages sind relativ kompliziert formatiert:

{ "error":
   { "code":"SABP_BEHV/100",
     "message":{ "lang":"de", 
	             "value":"Über 5000 kann nicht zurückgesetzt werden"},
				 "innererror":{ "application": {"component_id":"BC-ESI-ESF-GW", 
				                                "service_namespace":"/SAP/",
												"service_id":"ZDB_C_TRAVEL_PROC_M_SB_V2",
												"service_version":"0001"},
							    "transactionid":"4DD97CCD6B390060E00670159AB34AC7",
								"timestamp":"20241005195125.8177450",
								"Error_Resolution":{ "SAP_Transaction":"For backend a
Brandeis Consulting & Cadao

Best Practice Übung 5: Aufgabe 5.1 - Messageinhalt ausgeben

Damit wir uns einmal den Inhalt von oResult in onErrorCallFunction ansehen können, geben wir den Inhalt einfach einmal in die Console aus

console.log( oResult );

Wir sehen, dass in responseText die gesamte Fehlermeldung enthalten ist. Der Text der Message scheint über error.message.value erreichbar zu sein. Also ergänzen wir einen JSON Parser.

onErrorCallFunction: function ( oResult ){
    try{
        var oMessage = JSON.parse(oResult.responseText).error.message.value;
        MessageToast.show( oMessage );
    }catch(e){}
},

Fragestellungen

  • Was passiert beim Resetten einer Reise welche mehr als 5000 kostet?
  • Nicht perfekt, aber die Meldung wird angezeigt.
Brandeis Consulting & Cadao

Best Practice Übung 6: OData Messages ausgeben

Seit 1.118 gibt es eine neue zentrale Klasse sap.ui.core.Messaging welche uns beim Parsen und Ausgeben von OData Messages hilft. Bis 1.118 war dies sap.ui.core.message.MessageManager. In dieser Übung wollen wir nun OData Messages mit der neuen Klasse automatisch im Fußbereich anzeigen.

  • Aufgabe 6.1 Controller um Message Model erweitern
  • Aufgabe 6.2 Footer mit Buttons im View ergänzen
  • Aufgabe 6.3 Viewfragment und Controller Methoden
  • Aufgabe 6.4 Implementierung Clear Button
Brandeis Consulting & Cadao

Best Practice Übung 6: Aufgabe 6.1 - OData Messages - Controller

Dem Controller muss nun einmal die Message Klasse bekannt gegeben werden. Und in der Init Methode legen wir ein Model "message" an und registrieren den gesamten View.

Controller

sap.ui.define([
	"sap/ui/core/Messaging",
...
onInit: function () {
   ...
   this.getView().setModel(Messaging.getMessageModel(), "message");
   Messaging.registerObject(this.getView(), true);
Brandeis Consulting & Cadao

Best Practice Übung 6: Aufgabe 6.2 - OData Messages - Footer im View ergänzen

Jetzt ergänzen wir einen Footer mit zwei Buttons:

  • Button 1 - Öffnet ein Popup mit den Messages
  • Button 2 - Löscht die Messages und schließt den Footer
  • Der gesamte Footer wird nur angezeit, wenn im message-Model zumindest eine Message enthalten ist.

XML View

    <f:footer>
        <m:OverflowToolbar visible="{=${message>/}.length > 0}">
            <m:Button icon="sap-icon://alert"
                      text="{=${message>/}.length}"
                      type="Emphasized"
                      press="onMessagePopoverPress"/>
            <m:ToolbarSpacer/>
            <m:Button text="Clear" press="onClearPress"/>
        </m:OverflowToolbar>
    </f:footer>
</f:DynamicPage>

Fragestellungen

  • Was passiert beim Resetten einer Reise welche mehr als 5000 kostet?
Brandeis Consulting & Cadao

Best Practice Übung 6: Aufgabe 6.3 - OData Messages - Viewfragment

Es soll das Viewfragment MessagePopover.fragment.xml im View-Verzeichnis wie folgt angelegt werden.

<core:FragmentDefinition xmlns="sap.m"
	                 xmlns:core="sap.ui.core">
	<MessagePopover items="{message>/}"
		        initiallyExpanded="true">
		<MessageItem type="{message>type}"
			     title="{message>message}"
			     subtitle="{message>additionalText}"
			     description="{message>description}"/>
	</MessagePopover>
</core:FragmentDefinition>

Und im Controller benötigen wir für die Popupanzeige folgende Implementierung. Es gibt x Lösungen zur Anzeige eines Dialogs & Fragments. Das ist eine davon.

async onMessagePopoverPress(oEvent) {
    var oDialog = await this.loadFragment({
        name: "db.com.dbadvanced.View.MessagePopover" });
    oDialog.openBy( oEvent.getSource() );
},

Fragestellungen

  • Was passiert beim Resetten einer Reise welche mehr als 5000 kostet?
Brandeis Consulting & Cadao

Best Practice Übung 6: Aufgabe 6.4 - OData Messages - Clear Button

Nun die leichteste Aufgabe zur Übung 6. Wir benötigen eine Methode zum Löschen der Messages

Controller

onClearPress() {
    Messaging.removeAllMessages();
},
  • Der Footer wird nur bei vorhandenen Messages angezeigt und somit automatisch ausgeblendet

Fragestellungen

  • Was passiert beim "Reset" einer Reise welche mehr als 5000 kostet?
  • Was passiert beim "Reset" einer Reise welche mehr als 10.000 kostet?
Brandeis Consulting & Cadao

Best Practice Übung 7: XML View verbessern

In dieser Übung werden wir den XML View verbessern. Einerseits im Hinblick auf die Performance und anderseits um die Übersichtlichkeit zu erhöhen.

  • Aufgabe 7.1 $select Query bei Aggregats-Bindung
  • Aufgabe 7.2 Teile des Views mit XML fragments auslagern
Brandeis Consulting & Cadao

Best Practice Übung 7: Aufgabe 7.1 - $select Query in Aggregats-Bindung

Bis dato lesen wir aus dem Backend immer alle Attribute. Wir benötigen aber nur einen Teil, deshalb werden wir nun in der Aggregatsbindung nur die Felder aufnehmen, die wir benötigen.

<Table
rows="{ path: '/Travel',
        parameters: { select: 'TravelID, AgencyName, CustomerName, TotalPrice, CurrencyCode, OverallStatus, OverallStatusText' } }"
visibleRowCount="15"

Fragestellungen

  • Funktioniert alles noch korrekt?
  • Ist im $batch Call ersichtlich, dass nur mehr die gewünschten Felder "angefordert" werden?
Brandeis Consulting & Cadao

Best Practice Übung 7: Aufgabe 7.1 - Teile des Views auslagern

Der View ist bereits lange und beginnt unübersichtlich zu werden. Wie können wir den View übersichtlicher gestalten? Können wir Teile auslagern? Nested View?

  • Was finden wir in den Best Practices dazu?
Brandeis Consulting & Cadao

Best Practice Übungen - Was haben wir gemacht?

  • Übung 1: Generieren einer UI5 Freestyle Applikation
  • Übung 2: Spalten mit Buttons ergänzen
  • Übung 3: Base Controller
  • Übung 4: Backend Calls
  • Übung 5: Errorhandling
  • Übung 6: OData Messages optimiert
  • Übung 7: XML View verbessern
Brandeis Consulting & Cadao