SAPUI5 Advanced

OData V2 Übungen

Übung 1 - OData V2 Service generieren

Übung 2 - Generieren der UI5 Freestyle Applikation

Übung 3 - Anwendung wird CRUD

Übung 4 - Formatter & Bindings

Brandeis Consulting & Cadao

OData Übung 1: OData V2 Service generieren

In dieser Übung wird für die vorhandene Service Definition ZI_UI5_CUSTOMER_SD ein OData V2 Service Binding angelegt.

  • Aufgabe 1.1 - Service generieren
  • Aufgabe 1.2 - Metadaten prüfen
  • Aufgabe 1.3 - Daten prüfen
Brandeis Consulting & Cadao

OData V2 Übung 1 - Aufgabe 1.1 - Service generieren

Wir verwenden hier kein Fiori Elements, daher verwenden wir als Binding Type OData V2 - Web API. Dabei werden mögliche UI Annotations nicht berücksichtigt.

  • Service Binding Name: ZI_UI5_CUSTOMER_WAPI_V2_##
  • Binding Type: OData V2 - Web API
Brandeis Consulting & Cadao

OData V2 Übung 1 - Aufgabe 1.2 - Metadaten

Nun wollen wir uns das Service bzw. die Metadaten näher ansehen. Die Metadaten entweder im Gateway Client, Postman oder im Browser anzeigen.

Brandeis Consulting & Cadao

OData V2 Übung 1 - Aufgabe 1.3 - Daten

Als nächstes sehen wir uns die Daten / Customer näher an.

  • Wie viele Customer sind in Summe vorhanden? Customer/$count
  • Wie viele Einträge gibt es mit der City „Roma“ $filter=City eq 'Roma'&$inlinecount=allpages
  • Welcher „Roma“ Eintrag ist laut alph. Sortierung der erste Eintrag? $orderby=LastName asc
  • Wieviele Einträge aus Deutschland – ungleich der Stadt „Berlin“ sind vorhanden?
    • $filter=City ne 'Berlin' and CountryCode eq 'DE'&$inlinecount=allpages
  • Probieren Sie ruhig weitere Varianten aus:
Brandeis Consulting & Cadao

OData Übung 2: UI5 Freestyle App

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

  • Aufgabe 2.1 - Generieren der UI5 Freestyle Applikation
  • Aufgabe 2.2 - Manifest Anpassungen
  • Aufgabe 2.3 - View Anpassungen
  • Aufgabe 2.4 - Suchfeld implementieren
  • Aufgabe 2.5 - Suchfeld auf Vorname erweitern
  • Aufgabe 2.6 - Breitenangaben
Brandeis Consulting & Cadao

OData V2 Übung 2 - Aufgabe 2.1 - Generieren der UI5 Freestyle Applikation

In dieser Übung wird nun die UI5 Freestyle Anwendung mit dem BAS erstellt.

  • Starten Template Wizard mit STRG + SHIFT + P
  • Generator SAP Fiori application auswählen
  • Template Basic auswählen
  • Data Source, System (K1X) entsprechend auswählen
  • Generiertes OData V2 Service aus Übung 1 suchen/auswählen
  • Module: demov2##
  • Application namespace: de.ui5ws.demos
  • Keine Deployment Config, kein FLP, kein Advanced Options
  • Starten -> Warten -> Testen
Brandeis Consulting & Cadao

OData V2 Übung 2 - Aufgabe 2.2 - Manifest Anpassungen

Für spätere benötigen wir den BindingMode TwoWay. Daher müssen wir eine Einstellung in der Manifest anpassen.

"": {
        "dataSource": "mainService",
        "settings": { "defaultBindingMode": "TwoWay"},
        "preload": true
      }
Brandeis Consulting & Cadao

OData V2 Übung 2 - Aufgabe 2.3 - View Anpassungen

Der View soll ein Suchfeld, eine Tabelle und ein paar Buttons enthalten. Bitte ersetzen sie das Page Tag im View mit nachfolgendem Shell Tag. Keine Sorge, man muss es hier nicht lesen können. ;-)


<Shell id="shell">
		<App id="app">
			<pages>
				<Page id="page" title="Kunden OData V2">
					<content>
						<Table id="idTable"
						       inset="false"
							   growing="true"
							   growingThreshold="18"
						       items="{ path: '/Customer',
						                sorter: { path: 'CustomerId' } }">

							<headerToolbar>
								<OverflowToolbar>
									<Title text="Kunden" level="H2"/>
									<SearchField placeholder="Nachname oder Vorname" liveChange=".onSearch" width="80%" />
									<ToolbarSpacer/>
									<Button
										id="idOnSort"
										tooltip="Sort"
										icon="sap-icon://sort"
										press=".onSort" />
									<Button
										id="idOnCreate"
										tooltip="Create"
										icon="sap-icon://create"
										press=".onCreate" />
									<Button
										id="idOnDelete"
										tooltip="Delete"
										icon="sap-icon://delete"
										press=".onDelete" />

								</OverflowToolbar>
							</headerToolbar>

							<columns>
								<Column width="8em">
									<Text text="ID" />
								</Column>
								<Column width="10em">
									<Text text="Nachname" />
								</Column>
								<Column>
									<Text text="Vorname" />
								</Column>
								<Column>
									<Text text="Ort/Stadt" />
								</Column>
								<Column width="5em">
									<Text text="Land" />
								</Column>
								<Column width="22em">
									<Text text="eMail" />
								</Column>
								<Column width="12em">
									<Text text="Telefon" />
								</Column>
								<Column>
									<Text text="Ersteller" />
								</Column>
							</columns>
							<items>
							   <ColumnListItem vAlign="Middle">
							      <cells>
                                    <Text text="{CustomerId} " />
                                    <Text text="{LastName}" />
                                    <Text text="{FirstName}" />
                                    <Text text="{City}" />
                                    <Text text="{CountryCode}" />
                                    <Text text="{EmailAddress}" />
                                    <Link
                                        text="{PhoneNumber}"
                                        press="onPressPhoneNumber" />
                                    <Text text="{LocalCreatedBy} " />

								  </cells>
								</ColumnListItem>
							</items>
						</Table>
					</content>
				
					<footer>
						<OverflowToolbar id="idToolbar" enabled="false">
							<ToolbarSpacer/>
							<Button type="Accept" text="Sichern" press="onPressSave" enabled="true"/>
							<Button type="Reject" text="Zurücksetzen" press="onPressReset" enabled="true" />
						</OverflowToolbar>
					</footer>
				</Page>
			</pages>
		</App>
	</Shell>
Brandeis Consulting & Cadao

OData V2 Übung 2 - Aufgabe 2.3 - View Anpassungen

Wenn alles korrekt funktioniert, sollten nach einem Refresh bereits Daten angezeigt werden. Es ist bereits möglich Einträge zu ändern.

Brandeis Consulting & Cadao

OData V2 Übung 2 - Aufgabe 2.4 - Suchfeld implementieren

Im oberen Bereich des Views gibt es ein Suchfeld. Wir wollen nun die notwendige Implementierung dafür vornehmen.

Zuerst müssen wir dafür ein paar Module im View Controller aufnehmen:

    "sap/ui/model/Sorter",
    "sap/ui/model/Filter",
    "sap/ui/model/FilterOperator",
    "sap/ui/model/FilterType"

Nicht vergessen, die neuen Module in der Funktions-Signatur aufzunehmen:

function (Controller, Sorter, Filter, FilterOperator, FilterType ) {

Und nun noch die Methode onSearch wie folgt implementieren:

onSearch: function ( oEvent ) {
    var sQuery = oEvent.getSource().getValue();
    if (sQuery && sQuery.length > 0) {
        var oFilter = new Filter("LastName", FilterOperator.Contains, sQuery);
        this.byId("idTable").getBinding("items").filter( oFilter, FilterType.Server );
    } else {
        this.byId("idTable").getBinding("items").filter( );
    }
}
Brandeis Consulting & Cadao

OData V2 Übung 2 - Aufgabe 2.5 - Suchfeld auf Vorname erweitern

Nun soll der Filter, der aktuell nur auf den Nachnamen geht auch auf den Vornamen angewendet werden. Dafür tauschen wir die Erzeugung der Filterklasse aus.

var oFilter = new Filter({ filters: [ 
    new Filter({ path: "LastName", operator: FilterOperator.Contains, value1 : sQuery }),
    new Filter({ path: "FirstName", operator: FilterOperator.Contains, value1 : sQuery }) ], and: false })

Jetzt sollte der Filter auf Nach- und Voranme funktionieren.

Brandeis Consulting & Cadao

OData V2 Übung 2 - Aufgabe 2.6 - Breitenangaben

Jetzt wollen wir die Breite der eMail Adresse etwas vergrößern. Im Zuge dessen probieren wir verschiedene Breiten.

  • eMail Adresse soll 25em sein
  • Telefonnummer soll auf 12em angepasst werden
Brandeis Consulting & Cadao

OData Übung 3: CRUD

In dieser Übung werden wir nun nach und nach die derzeitige Listausgabe zu einer Liste mit Änderungsmöglichkeit machen.

Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.1 - Eingabefelder

Wir beginnen im View und tauschen die aktuellen Anzeigefelder durch Inputfelder aus.

<ColumnListItem vAlign="Middle">
    <cells>
    <Text text="{CustomerId} " />
    <Input id="idInputLastName" value="{LastName}" liveChange="onDataChange" change="onDataChange" required="true" />
    <Input value="{FirstName}" liveChange="onDataChange" change="onDataChange"/>
    <Input value="{City}" liveChange="onDataChange" change="onDataChange"/>
    <Input value="{CountryCode}" liveChange="onDataChange" change="onDataChange"/>
    <Input value="{EmailAddress}" liveChange="onDataChange" change="onDataChange"/>
    <Input value="{PhoneNumber}" liveChange="onDataChange" change="onDataChange"/>
    <Text text="{CreatedBy} " />
    </cells>
</ColumnListItem>

Hinweise

  • liveChange reagiert in Echtzeit auf Eingaben, change wird erst bei "enter" ausgelöst

Fragestellungen

  • Wie sieht das Ergebnis aus?
  • Können die Einträge geändert werden?
  • Funktioniert der Filter nach wie vor?ui5
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.2 - Buttonleiste (Sichern, Zurücksetzen) aktivieren

Sobald der Anwender Änderungen vornimmt, sollen die beiden Buttons im Fußbereich aktiv werden. Im View ist dafür bereits alles vorbereitet. Im Controller ist folgende Methode zu implementieren.

Methode onDataChange muss wie folgt implementiert werden:

onDataChange: function( oEvent ){
    if ( this.getView().getModel().hasPendingChanges() ){
        this.byId("idToolbar").setEnabled( true );  
    } else {
        this.byId("idToolbar").setEnabled( false ); 
    }
},

Hinweise

  • mit hasPendingChanges wird geprüft, ob "offene" Änderungen im Model vorhanden sind
  • mit .setEnabled wird die gesamte Buttonleiste aktiv oder inaktiv

Fragestellungen

  • Wird die Buttonleiste (Sichern, Zurücksetzen) aktiv, sobald man Änderungen vornimmt?
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.3 - Zurücksetzen implementieren

Wenn ein Anwender nicht gesicherte Änderungen zurücksetzen will, kann dies mit dem Button „Zurücksetzen“ vorgenommen werden. Im Coding wird geprüft, ob es offene Änderungen gibt, und wenn ja werden die Änderungen des OData Models zurückgesetzt.

Dafür ist die Methode onPressReset zu implementieren:

onPressReset: function (oEvent){
    if ( this.getView().getModel().hasPendingChanges() ){
        this.getView().getModel().resetChanges();
        MessageToast.show( "Alle offenene Änderungen wurden zurückgesetzt", { width: "25em" } ); 
    } else {
        MessageToast.show( "Keine offenen Änderungen", { width: "25em" } );     
    };
},

Hinweise

  • Wir verwenden hier erstmals MessageToast. Das Module sap/m/MessageToast muss natürlich oben aufgenommen werden. Auch das MessageToast in der Signatur ganz oben nicht vergessen.

Fragestellungen

  • Können gemachte Änderungen zurückgesetzt werden?
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.4 - Buttons ggf. wieder deaktivieren

Nach einem Zurücksetzen oder Sichern sollen die Buttons wieder inaktiv werden. Dafür rufen wir einfach die bereits existierende onDataChange Methode am Ende der neuen Methode onPressReset auf.

this.onDataChange();

Fragestellungen

  • Werden die Buttons wieder inaktiv nach einem Zurücksetzen?
  • Und bei neuerlichen Änderungen wieder aktiv?
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.5 - Save implementieren

Jetzt wird es spannend - jetzt müssen wir die Methode onPressSave implementieren. Dann sollten die Änderungen auch ins Backend gesichert werden.

onPressSave: function (oEvent){
    if ( this.getView().getModel().hasPendingChanges( ) ){      
        this.getView().getModel().submitChanges( { 
                                    success: function( oEvent ){ alert( "Erfolgreich" ) },
                                    error: function( oEvent ){ alert( "Fehlerhaft" ) } } );
    } else {
        MessageToast.show( "Keine offenen Änderungen", { width: "25em" } );     
    };          
},

Hinweise

  • Modeländerungen werden mit submitChanges übertragen
  • success und error können implementiert werden
  • Fürs erste reicht uns die Ausgabe mit Alert

Fragestellungen

  • Funktioniert das Sichern der Änderungen?
    • Kontrolle durch Refresh
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.6 - Save - Handlermethoden Implementieren

Nachdem die Verbuchung aus 3.4 funktioniert, machen wir nun einer schönere Implementierung der Safe bzw. Error Methoden. Bei Success und Error wollen wir zwei neue Methoden des gleichen Controllers aufrufen. Die Lösung sieht wie folgt aus:

            onPressSave: function (oEvent){

                var that = this;

                if ( this.getView().getModel().hasPendingChanges( ) ){      
                    this.getView().getModel().submitChanges( { 
                                                success: function( oEvent ){ that.onSuccessUpdate( oEvent ) },
                                                error: function( oEvent ){ that.onErrorUpdate( oEvent ) } } );
                } else {
                    MessageToast.show( "Keine offenen Änderungen", { width: "25em" } );     
                };          
            },

            onSuccessUpdate: function( oEvent ){
                MessageToast.show( "Verarbeitung Erfolgreich" );
            },

            onErrorUpdate: function( oEvent ){
                MessageToast.show( "Fehler bei der Verarbeitung" );
            },

Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.7 - Save - Fehler im SAVE behandeln

Die Verarbeitung der Daten erfolgt als OData Batch. Das heißt – die Übermittlung des Batches kann erfolgreich sein, die Verbuchung einer der enthaltenen Entitäten kann jedoch fehlerhaft sein.

Dies muss separat im onSuccessUpdate geprüft und behandelt werden. In etwa wie folgt:

	try {
		if (oEvent.__batchResponses[0].response.statusCode >= 400) {
			MessageToast.show( "Fehler beim Sichern" );
		}   

	} catch (err) {
	};

	try {
		if (oEvent.__batchResponses[0].__changeResponses[0].statusCode = 201 ) {
			MessageToast.show( "Änderung erfolgreich gesichert" );
			this.onDataChange();
		}
	} catch (err) {
	}
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.8 - Anlegen neuer Einträge

Rechts oben im View gibt es einen Button für die Neuanlage. Die notwendige Implementierung kommt jetzt. Wir legen hier einen neuen Eintrag an. Im "echten" Leben würden wir vermutlich noch ein Popup mit Inputfeldern anbieten. Wir legen den Datensatz jedoch direkt an. Die Daten werden aber erst beim Sichern angelegt.

Dazu brauchen wir eine Implementierung in der Methode onCreate

onCreate: function() {
                this.getView().getModel( ).createEntry( "/Customer", 
					{ properties: { LastName : 'Demo ##' } } );
                this.onDataChange();   
            },

Hinweise

  • Die Neuanlage wird er mit dem Button Sichern ans Backend geschickt

Fragestellungen

  • Funktioniert das Anlegen neuer Einträge?
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.9 - Bestehende Einträge löschen

Wir wollen auch Einträge löschen. Dafür müssen wir im View zuerst einmal im Tabel Contol die Eigenschaft mode auf SingleSelectLeft setzen. Wir könnten auch MultiSelect verwenden:

<Table id="idTable"
		inset="false"
		growing="true"
		growingThreshold="18"
		items="{ path: '/Customer',
				sorter: { path: 'CustomerId' } }"
		mode="SingleSelectLeft">

Für das Löschen ist folgende Methode zu implemenieren:

onDelete: function() {
	var oSelectedItems = this.byId("idTable").getSelectedItems();

	if ( oSelectedItems ) {
		for (var i = 0; i < oSelectedItems.length; i++) {
			var sPath = oSelectedItems[ i ].getBindingContext().getPath();
			this.getView().getModel( ).remove( sPath );
		}
		this.onDataChange();
	}
},
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.9 - Einträge löschen - Meldungen

Nun machen wir die Implementierung des Löschen etwas besser und lagern die Meldungen in eigene Methoden aus:

onDelete: function() {

	var that = this;

	var oSelectedItems = this.byId("idTable").getSelectedItems();

	if ( oSelectedItems ) {
		for (var i = 0; i < oSelectedItems.length; i++) {
			var sPath = oSelectedItems[ i ].getBindingContext().getPath();
			this.getView().getModel( ).remove( sPath, { success: function( oEvent ) { that.onDeleteSuccess( oEvent ) },
														error: function( oEvent ){ that.onDeleteError( oEvent ) } });
		}
		this.onDataChange();
	}
},

onDeleteSuccess: function( oEvent ){
	MessageToast.show( "Daten gelöscht" );
},

onDeleteError: function( oEvent ){
	MessageToast.show( "Fehler beim Löschen" );
},
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.10 - Sortierung nach Nachnamen

Jetzt wollen wir noch den Sort-Button implementieren und eine Sortierung nach Nachnamen erreichen. Wir verwenden hier einen Trick. – Zuerst „unbinden“ wir die Daten, dann binden wir diese neu - mit neuer Sortierung.

onSort: function( oEvent ) {
                var oTable = this.byId("idTable");
                var oSorter = [];
                var oTemplate = oTable.getBindingInfo("items").template;
                oSorter.push(new Sorter('LastName',false));
                oTable.unbindItems();
                oTable.bindItems( { path: "/Customer", template: oTemplate,
                                                       sorter: oSorter } ); 
            },

Hinweise

  • Die Implementierung ist nicht perfekt, sie soll nur zeigen wir man Bindings dynamisch ändern kann.
    • z.B. wird hier ein bestehender Filter nicht berücksichtigt
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.11 - Update eines Elements - mit SetProperty am Model

  • Neuen Button neben Sort,Create,Delete: Update
    • Icon sap-icon://edit
    • Methode onEdit
    • Implementierung Methode onEdit im Controller
      • Prüfen ob Zeile selektiert wurde
      • Bei ausgewhältem Eintrag die Telefonnummer auf +49 999 ändern
      • Als Vorlage z.B. die Delete Implementierung übernehmen
      • Änderung Telefonnummer mit: that.getView().getModel( ).setProperty( sPath + '/PhoneNumber', '+49 999' )
Brandeis Consulting & Cadao

OData V2 Übung 3 - Aufgabe 3.12 - Update eines Elements - direkt Call

  • Variante 2 - OData direkt ändern
	var oUpdateData = {};
	oUpdateData.PhoneNumber='+49 888';
	that.getView().getModel( ).update( sPath, oUpdateData );
Brandeis Consulting & Cadao

OData V2 Übung 4 - Aufgabe 4.1 - Formatter

Die Ausgabe der Customer ID soll mit einem formatter angepasst werden. Konkret soll jede Customer-ID mit C- beginnen. Mit dem Formatter können wir zur Laufzeit die Ausgabe beeinflussen.

Hinweis

  • Formatter können nur in OneWay Binding verwendet werden. Daher nicht z.B. bei Input-Feldern
<Text text="{ path: 'CustomerId', formatter : '.formatterCustomerId' } " />
formatterCustomerId: function(customerid){
	return 'C-' + customerid;
},
Brandeis Consulting & Cadao

OData V2 Übung 4 - Aufgabe 4.2 - Expression Binding

Alle Zeilen aus Deutschland sollen vom Status her grün eingefärbt werden. Dafür wird die Eigenschaft highlight des ColumnListItem verwendet. Mögliche Werte sind z.B. Success, None, Error, ..

Mit Expression-Binding lassen sich in der View bestimmte Funktionen direkt im Binding ausführen. Expression-Binding sieht folgendermaßen aus: {= <expression>}

Auf Models kann per ${..} zugegriffen werden.

<ColumnListItem vAlign="Middle" highlight="{= ${CountryCode} === 'DE' ? 'Success' : 'None' }"	>

Weitere Beispiele:

editable="{= ${CountryCode} === 'DE' ? true : false }"
editable="{= ${CountryCode} === 'DE'}"
Brandeis Consulting & Cadao

OData V2 Übung 4 - Aufgabe 4.3 - Property Metadata Binding

Im Feld CountryCode kann man beliebig lange Werte eingeben. Nicht gut. Wird ein Wert länger als 3 Stellen übergeben, kommt es im Backend bei der Verbuchung zu einem Fehler. Mit der Eigenschaft maxLength="3" könnten wir das Land auf die Länge 3 limitieren.

Eine noch bessere Möglichkeit ist, die maximale Länge aus den Metadaten zu verwenden.

Syntax um z.B. die max Länge aus den Metadaten zu binden: {/#<EntityType>/<Property>/@maxLength}

Hinweis

  • Der Inhalt von maxLength wird als "String" geliefert. Daher hier noch zusätzlich das parseInt
<Input value="{CountryCode}" liveChange="onDataChange" change="onDataChange" maxLength="{= parseInt( ${/#CustomerType/CountryCode/@maxLength} )}"/>
Brandeis Consulting & Cadao