SAP-Wissen aus erster Hand.

Leseprobe

Mit diesem Buch tauchen Sie ein in die Anwendungsentwicklung mit SAPUI5 und lernen alles, was Sie über Design, Programmie- rung und Betrieb der Apps wissen müssen. In dieser Leseprobe erläutern die Autoren die allgemeine Nutzung von SAPUI5 sowie deren Modelltypen und erörtern die unterschiedlichen Formen des Data Bindings.

»Modelle und Bindings« »Einleitung«

Inhaltsverzeichnis

Index

Die Autoren

Leseprobe weiterempfehlen

Christiane Goebels, Denise Nepraunig, Thilo Seidel SAPUI5 – Das umfassende Handbuch 699 Seiten, gebunden, November 2016 79,90 Euro, ISBN 978-3-8362-4456-5

www.sap-press.de/4303 4456.book Seite 161 Mittwoch, 9. November 2016 10:03 10

Kapitel 5 In diesem Kapitel erörtern wir die allgemeine Nutzung von SAPUI5 und die darin enthaltenen Modelltypen sowie das Data Binding.

5 Modelle und Bindings

Im vorherigen Kapitel 4, »Aufbau von MVC-Anwendungen«, haben wir er- läutert, wie Modelle als Datencontainer funktionieren, in denen sämtliche Geschäftsdaten enthalten sind, die in Ihrer Anwendung verarbeitet werden. SAPUI5 wird mit verschiedenen vordefinierten, einsatzbereiten Modellklas- sen bereitgestellt. In der Beispielanwendung haben Sie schon ein JSON- und ein Ressourcenmodell in Aktion gesehen. In diesem Kapitel erklären wir die- se Modelltypen genauer, und Sie erfahren mehr über die Bindungsfunktio- nalität, die in allen Anwendungen zum Einsatz kommt.

Data Binding beinhaltet das Verbinden von Daten, die in einem bestimmten Modell in einer Anwendung verfügbar sind, mit einem bestimmten Teil der Benutzeroberfläche auf dem Bildschirm. Diese Verbindung kann entweder unidirektional oder bidirektional sein. Bei der ersten Verbindung werden die Daten aus dem Modell bereitgestellt, und die Modelldaten bleiben un- berührt, wenn sie in der Benutzeroberfläche geändert werden. Bei der letz- ten Verbindung werden die Daten aus der Benutzeroberfläche und dem Modell laufend synchronisiert, wie es bereits im Beispiel des letzten Kapi- tels bei den Eingabefeldern gezeigt wurde.

Bei den meisten Modellen können Sie selbst entscheiden, ob Sie eine uni- oder eine bidirektionale Bindung verwenden möchten. Eine unidirektionale Bindung bedeutet allerdings nicht, dass die Daten in solch einem Modell gar nicht aktualisiert werden können: Sie müssen Sonderaktionen ausführen, um das Modell zu aktualisieren. Warum das so ist, wird deutlich, wenn wir einen genaueren Blick auf die Menge an Daten werfen, auf die unsere An- wendung zugreifen kann, und prüfen, woher diese Daten stammen. Zuerst betrachten wir ein JSON-Beispiel.

161 4456.book Seite 162 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 163 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Verwenden von Modellen – ein JSON-Beispiel 5.1

5.1 Verwenden von Modellen – ein JSON-Beispiel Im Hintergrund werden zwei Optionen für das JSON-Modell unterschieden: ob es 1) eine URL oder 2) ein Objekt als Parameter für den Konstruktor emp- JSON-Modelle sind clientseitige Modelle. Dies bedeutet, dass die Anwen- fangen hat. Dieses Mal wurde eine URL übergeben, die von der Konstruktor- dung nach der Instanziierung des Modellobjekts und dem Laden der Daten funktion des Modells erkannt wird. Die Funktion versucht dann automa- Zugriff auf alle im Modell enthaltenen Daten hat. tisch, die Datei mit der Funktion setData des Modells aus der URL zu laden. Andere Modelle, wie z. B. das OData-Modell, sind serverseitige Modelle. Bei Dies können Sie erkennen, wenn Sie einen Blick auf die Konstruktorfunktion der Instanziierung eines bestimmten Modellobjekts werden Daten nicht au- werfen (siehe Listing 5.1). tomatisch geladen. Die Daten müssen angefordert werden und werden dann var JSONModel = ClientModel.extend("sap.ui.model.json.JSONModel", { bei Bedarf geladen. Dies kann entweder über bewusste Aktionen im Anwen- constructor : function(oData) { dungscode erfolgen (z. B. Aufruf der entsprechenden Funktionen im Modell) ClientModel.apply(this, arguments); if (oData && typeof oData == "object") { oder automatisch geschehen, wenn die Daten aus solch einem Modell mit this.setData(oData); bestimmten Bindungstypen an ein bestimmtes Bildschirmelement gebunden } sind. Das Modellobjekt selbst übernimmt dann die Anforderung der Daten }, aus dem Service. Weitere Details hierzu erhalten Sie im nächsten Kapitel, wenn wir genauer auf das oData-Modell eingehen. metadata : { publicMethods : ["setJSON", "getJSON"] Wie im vorangehenden Kapitel verwenden wir nun ein JSON-Modell und } prüfen, wie dieses in der Anwendung eingesetzt werden kann und wie die }); unterschiedlichen Bindungstypen aus SAPUI5 angewendet werden können. Listing 5.1 sap.ui.model.JSONModel-Konstruktor

Wurden die Daten erfolgreich abgerufen, werden sie im Modellobjekt, ge- 5.1.1 Instanziierung und Laden der Daten nauer gesagt in einer Eigenschaft des Modells mit dem Namen oData, gespei- Wir rekapitulieren zuerst die Modellstruktur aus der Beispielanwendung, chert. Beachten Sie, dass diese Eigenschaft nicht für den direkten Zugriff ge- und greifen wir nochmals auf, was wir im vorangehenden Kapitel erreicht dacht ist und hier nur erwähnt wird, um zu verdeutlichen, wo die Daten haben. Alle Geschäftsdaten, die wir für unsere Anwendung benötigen, lie- abgelegt werden. gen uns in einer JSON-Struktur vor. Wie Sie gesehen haben, ist das Instanzi- Neben diesem automatischen Laden bei der Instanziierung gibt es eine wei- ieren eines JSON-Modells mit der Konstruktorfunktion der entsprechenden tere Möglichkeit, um die Anforderung von Daten auszulösen. Das JSON-Mo- Modellklasse ziemlich leicht: dell verfügt außerdem über eine Methode loadData, mit der wir das Laden // model creation and loading the data von Daten, wie es in Listing 5.2 dargestellt ist, manuell auslösen können. var oAppModel = sap.ui.model.json.JSONModel(this.getMetadata(). getConfig().serviceUrl); // model creation and loading the data var oAppModel = sap.ui.model.json.JSONModel(); Sie wissen bereits, was hier geschieht: SAPUI5 erstellt ein neues Objekt mit dem Prototyp sap.ui.model.json.JSONModel. // loading the JSON data from the URL and storing it in the model oAppModel.loadData("service/data.json"); Als Nächstes benötigen wir einige Daten für dieses Modell, die den Controls Listing 5.2 Instanziieren des Modells und manuelles Laden der Daten in unserer Anwendung zur Verfügung stehen sollen. Wie zuvor verwenden wir nicht einfach ein JSON-Objekt, sondern laden die Daten aus einer sepa- Diese Komfortfunktion ist tatsächlich ein Wrapper für eine XHR-Anfrage, die raten Datei, um die Antwort zu simulieren, die wir von einem Service erhal- wir ansonsten selbst erstellen müssten, wenn wir selbst entscheiden möch- ten würden. ten, wann die Anforderung zum Laden von Daten ausgelöst werden soll. Wir

162 163 4456.book Seite 164 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 165 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Verwenden von Modellen – ein JSON-Beispiel 5.1

erhalten so eine Möglichkeit, um einen Teil des aus der übergeordneten 5.1.2 Zugriff auf Modellwerte sap.ui.model.Model Klasse vererbten Standardverhaltens zu beeinflussen. Sie erfahren nun, wie Sie über die Methoden getProperty und setProperty Wir lassen das Standardverhalten für den Moment aber unverändert und se- auf Werte in einem JSON-Modell zugreifen und diese manipulieren können. hen uns genauer an, was geschieht, wenn die Funktion loadData aufgerufen Um allerdings sicherzustellen, wann die Daten im Modell verfügbar sein sol- wird (siehe Listing 5.3; Codezeilen, die derzeit nicht relevant sind, haben wir len und wann wir damit arbeiten können, müssen wir das Ereignis request- ausgelassen). Completed anhängen.

JSONModel.prototype.loadData = function(sURL, oParameters, bAsync, Wechseln wir für die restliche Einführung in das Data Binding zu einem klei- sType, bMerge, bCache, mHeaders){ neren und isolierteren Anwendungsbeispiel. Dieses nennen wir Databinding [...] First Steps. Mit diesem Beispiel werden unsere ersten zaghaften Schritte im this.fireRequestSent({url : sURL, type : sType, async : bAsync, Modell transparenter. Wir kehren gelegentlich zum größeren Anwendungs- headers: mHeaders, info : "cache=" + bCache + ";bMerge=" + bMerge, infoObject: {cache : bCache, merge : bMerge}}); beispiel zurück, um das neu Erlernte umzusetzen. this._ajax({ Die Datei index.html für diese neue, kleine Beispielanwendung sehen Sie in [...] success: function(oData) { Listing 5.4. [...] that.setData(oData, bMerge); that.fireRequestCompleted({url : sURL, type : sType, async : bAsync, headers: mHeaders, info : "cache=" + bCache + ";bMerge= " + bMerge, JSON First Steps infoObject: {cache : bCache, merge : bMerge}, success: true}); Abbildung 5.1 Erste Anzeige der Beispielanwendung

In dieser Anwendung rufen wir zunächst die Daten aus unserer Modelldatei manuell ab, indem wir die Funktion loadData aufrufen. Danach möchten wir auf einen der Werte im Modell zugreifen und diesen bearbeiten. Wir kön- Listing 5.4 Erste JSON-Beispielanwendung nen die Methoden getProperty und setProperty hierzu verwenden, die für JSON-Modelle selbst implementiert sind. Mit diesen Methoden können Sie In dieser Beispielanwendung sind auch JSON-Daten in einer Datei mit dem auf bestimmten Knoten im Modell operieren und auf die Werte mit der Pfad- Namen data.json enthalten, die sich im Ordner service befinden (wie in den syntax, die Sie kurz in Kapitel 4, »Aufbau von MVC-Anwendungen«, gesehen vorangehenden Beispielen). Die Datei sieht derzeit wie in Listing 5.5 aus. haben, zugreifen. Sie erfahren, wie Sie den bald benötigten Pfad ermitteln. { Zuerst möchten wir aber auf ein Timing-Problem eingehen, das hier vorliegt. "Suppliers": [ Dieses Problem wird am offensichtlichsten, wenn Sie die Anwendung in { einem Browser ausführen und das Modellobjekt zur Laufzeit prüfen. "ID": 0, "Name": "Exotic Liquids", Wenn Sie den Effekt selbst sehen möchten, setzen Sie einen Breakpoint "Address": { direkt nach der Zeile des Codes, in der das Modell instanziiert ist, und be- "Street": "NE 228th", trachten das Modellobjekt im Debugger Ihres Browsers. Sie können erken- "City": "Sammamish", "State": "WA", nen, dass es im Modell noch keine bearbeitbaren Modelle gibt (siehe Abbil- "ZipCode": "98074", dung 5.2). "Country": "USA" } }, { "ID": 1, "Name": "Tokyo Traders", "Address": { "Street": "NE 40th", "City": "Redmond", "State": "WA", "ZipCode": "98052", "Country": "USA" Abbildung 5.2 oModel in der Entwicklertools-Konsole von Google Chrome, bevor die Daten } geladen wurden } ] } Wenn wir den nächsten Breakpoint in der Funktion setzen, rufen wir re- Listing 5.5 JSON-Modell questCompleted auf. War die Anforderung erfolgreich, wird Ihnen sofort ein Ergebnis wie in Abbildung 5.3 angezeigt, wenn Sie diesen Breakpoint errei- Wenn Sie diese Anwendung ausführen, wird ein nicht übermäßig befüllter chen. Bildschirm angezeigt (siehe Abbildung 5.1).

166 167 4456.book Seite 168 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 169 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Verwenden von Modellen – ein JSON-Beispiel 5.1

wir unsere Control-Eigenschaft binden möchten. Daher greift dieser Pfad auf die hervorgehobenen Werte im nachstehenden Modellcode zu:

{ "Suppliers":[ { "ID":0, "Name":"Exotic Liquids", "Address":{ "Street":"NE 228th", "City":"Sammamish", "State":"WA", "ZipCode":"98074", "Country":"USA" Abbildung 5.3 oModel in der Entwicklertools-Konsole von Google Chrome, nachdem die }, Daten geladen wurden [...] }, Sie können sehen, dass die Eigenschaft oData des Modells mit den entspre- { chenden Daten aus der Datei data.json befüllt wurde. "ID":1, "Name":"Tokyo Traders", Bearbeiten wir nun die Daten mit den zuvor genannten Methoden. Die Call- "Address":{ back-Funktion wird nur aufgerufen, wenn das Ereignis requestCompleted "Street":"NE 40th", ausgelöst wurde: "City":"Redmond", "State":"WA", oModel.attachRequestCompleted(function(oEvent){ "ZipCode":"98052", // callback function here "Country":"USA" }); }, [...] Befüllen wir nun diese Callback-Funktion. Um Zugriff auf die Werte im Mo- } dell zu erhalten, benötigen Sie nur eine Information: den Pfad zum Knoten, ] mit dem Sie arbeiten möchten. }

Die meisten Modelle in SAPUI5 besitzen eine hierarchische Struktur, über Listing 5.6 Pfad zu einem bestimmten Knoten im Modell die Sie auf die Knoten und Werte zugreifen können, wenn Sie den jeweiligen Pfad angeben. Mit der entsprechenden Syntax werden einfach die Modell- Mit dem führenden Schrägstrich wird angegeben, dass dieser Pfad am Mo- knotenebenen getrennt, was zu dem gewünschten Wert mit Schrägstrichen dellstamm beginnt. Ist ein führender Schrägstrich vorhanden, bedeutet das, führt: dass ein absoluter Pfad vorliegt. Wir können auch relative Pfade verwenden, die praktischer sind, wenn wir in Abschnitt 5.2, »Property Binding«, die Bin- /Suppliers/0/Name dungskontexte besprechen.

Über diesen Pfad erfolgt der Zugriff auf den Wert der Eigenschaft Name, die Nachdem wir nun den Pfad kennen, können wir ihn als Parameter in den dem ersten Lieferanten im Modell der Beispielanwendung zugewiesen ist. Methoden getProperty und setProperty in der Anwendung innerhalb der Der erste Teil des Pfads weist auf die Lieferantensammlung im Modell, im Callback-Funktion verwenden. Wir geben den Pfad zum Wert, auf den wir nächsten Teil können wir die Reihenfolge der Lieferanten im Modell aus- als Parameter zugreifen möchten, an die Methode getProperty im Modell wählen, und der letzte Teil verweist auf die bestimmte Eigenschaft, mit der weiter.

168 169 4456.book Seite 170 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 171 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Property Binding 5.2

Anschließend ändern wir den Wert nach Bedarf und geben diesen geänder- widergespiegelt. Da wir derzeit eine bidirektionale Bindung verwenden, gilt ten Wert über die Methode setProperty wieder an das Modell zurück. Diese dies auch in umgekehrter Reihenfolge. Methode verwendet den Pfad als Parameter sowie den Wert, den Sie zuwei- Sie benötigen zwei Parameter, um eine Bindung zwischen einer Control-Ele- sen möchten. Schließlich sieht der Code wie in Listing 5.7 aus. menteigenschaft und einem Wert im Modell herzustellen: oModel.attachRequestCompleted(function(oEvent){ ̈ //get and manipulate particular value: den Pfad zum Wert im Modell var sSupplierName = oModel.getProperty("/Suppliers/0/Name"); ̈ den Namen der Eigenschaft, die Sie binden möchten sSupplierName = sSupplierName + " Sammamish"; oModel.setProperty("/Suppliers/0/Name", sSupplierName); Als Nächstes betrachten wir die Methoden zum Binden der Eigenschaft eines }); Controls. Anschließend gehen wir auf den Einsatz von Datentypen und die Listing 5.7 Finale Callback-Funktion für das Ereignis requestCompleted Definition eigener Datentypen ein.

Wenn Sie den Code speichern und diese Seite anzeigen lassen, sehen Sie, 5.2.1 Methoden zum Binden der Eigenschaft eines Controls dass der Wert für den ersten Lieferanten tatsächlich im Modell und in der Benutzeroberfläche geändert wurde. Letzteres geschieht, da das Modell Es gibt zwei grundsätzliche Methoden, um die Eigenschaft eines Controls zu selbst erkennt, dass die Daten geändert wurden, und die Benutzeroberfläche binden: darüber benachrichtigt, dass ein Wert aktualisiert wurde. ̈ Control-Einstellungen

getProperty Sie können das Binding in dem Objekt für initiale Settings im Konstruk- toraufruf eines Controls erzeugen, wenn Sie nicht deklarative View-Typen Die Methode getProperty gibt nicht zwangsläufig einen einfachen Wert zurück, nutzen. Oder Sie können die Binding-Informationen einfach statt eines fi- sondern je nach Art der im entsprechenden Pfad gefundenen Daten ein Objekt xen Werts in das gewünschte Attribut schreiben wenn Sie z. B. einen XML- oder mehrere Objekte. Wenn die Funktion getProperty auf den Pfad /Sup- View verwenden. pliers/0 verweist, wird ein JavaScript-Objekt zurückgegeben, das mit Eigen- schaften aus dem JSON-Modell befüllt ist. ̈ bindProperty Diese Methode kann für das Control jederzeit im Code verwendet werden, Betrachten wir als Nächstes, wie diese bestimmte Verbindung hergestellt um das System darüber zu informieren, an welchen Wert im Modell eine wird, da sie die Controls innerhalb unserer Anwendung bereits verwenden. Eigenschaft gebunden werden soll.

In den nächsten beiden Unterabschnitten gehen wir auf diese beiden Metho- den ein und geben Beispiele für deren Einsatz. Dann erläutern wir die Ver- Property Binding 5.2 wendung von Datentypen und die Definition eigener Datentypen.

Da das Modell nun vorliegt, stehen uns die benötigten Informationen über dessen Struktur und Inhalte sowie die Werte aus dem Modell zur Verfügung, Control-Einstellungen die wir in der Anwendung anzeigen möchten. Wie in Kapitel 4, »Aufbau von Wenn zum Erzeugen des Bindings die Control-Settings verwendet werden, MVC-Anwendungen«, erläutert, ist Property Binding eine Möglichkeit, um weisen geschweifte Klammern um den Eigenschaftswert das Framework an, Werte aus einem Modell auf dem Bildschirm anzuzeigen. Property Bindings dass das normale Parsen des Strings nicht stattfinden soll. Stattdessen soll ein ermöglichen uns, die Eigenschaften der Controls mit bestimmten Werten in Binding erstellt werden. einem Modell zu verbinden. Sobald solch eine Verbindung aufgebaut wurde, wird jede Änderung am Wert in einem Modell in der Control-Eigenschaft In Abbildung 5.4 haben wir ein einfaches Text-Controls mit der Konstruktor- funktion im JavaScript-Code instanziiert:

170 171 4456.book Seite 172 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 173 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Property Binding 5.2

var oText = new sap.m.Text({ Geben Sie einen anderen Wert in das Textfeld ein, und sehen Sie, was ge- text: "{/Suppliers/0/Name}" schieht, wenn Sie die (¢)-Taste drücken oder aus dem Feld heraus navigie- }); ren. Der eingegebene Wert wird sofort für den Text des Controls text über- Wir geben einen Wert an den Konstruktor weiter, der der Eigenschaft text nommen und über dem Eingabefeld angezeigt. des Controls zugewiesen ist. Dieser Wert enthält nun den Pfad zu dem Wert Live-Wert im JSON-Modell. Sobald der Wert im JSON-Modell aktualisiert wird, wird auch der Wert der Control-Eigenschaft aktualisiert. Der Live-Wert des Eingabefelds wird nur im Wertattribut des Controls reflektiert, wenn ein Änderungsereignis ausgelöst wurde. Dieses Änderungsereignis wird nor- In einem Szenario mit bidirektionaler Bindung funktioniert das auch in die malerweise ausgelöst, wenn ein Anwender eine Taste wie z. B. (¢) drückt oder andere Richtung. Wenn Sie das Control text durch eine Eingabe ersetzen, das Feld anderweitig durch Klicken oder Navigieren verlässt. erhalten Sie sofort die Möglichkeit, die Modellwerte anzupassen. Zum Be- weis können wir ein weiteres Control zu unserer Beispielanwendung hinzu- In XML-Views können die spezifischen Eigenschaften eines Controls so ge- sap.m.Input fügen: . bunden werden wie in den Einstellungen einer Control-Instanziierung in In Listing 5.8 instanziieren wir ein Control sap.m.Input und platzieren es in JavaScript. Sie müssen nur geschweifte Klammern in das Attribut am ent- content div. sprechenden Tag für das Control einfügen:

var oInput = new sap.m.Input({ value: "{/Suppliers/0/Name}" }); bindProperty oInput.placeAt("content"); Listing 5.8 sap.m.Input-Instanziierung Wenn Sie die Eigenschaft eines Controls nicht bei der Instanziierung, son- dern zu einem späteren Zeitpunkt im Code an einen Modellwert binden Wenn Sie diesen Code zum Beispiel hinzufügen, sollte die Anwendung wie möchten, können Sie die Methode bindProperty verwenden, die in jedem in Abbildung 5.4 aussehen. Control in SAPUI5 bereitgestellt wird:

oInput.bindProperty("value", {path: "{/Suppliers/0/Name}"});

Möchten Sie den automatischen Datenfluss unterdrücken und den bidirek- tionalen Bindungsmodus für ein bestimmtes Control deaktivieren, können Sie dies am Control wie folgt festlegen:

oInput.bindProperty("value", { Abbildung 5.4 Beispielanwendung mit sap.m.Input path: "{/Suppliers/0/Name}" mode: sap.ui.model.BindingMode.OneWay Dem Eingabefeld wurde derselbe Wert wie dem Text darüber zugewiesen. }); Bei einer bidirektionalen Bindung steckt aber mehr dahinter, als hier direkt In letzterem Beispiel verwenden wir die Objektliteral-Syntax zum Definieren zu sehen ist. Wie zuvor erwähnt, sind beide Controls nun mit demselben der Bindung, wie wir es für die Bindung im Konstruktoraufruf gezeigt haben. Wert aus dem Modell verbunden. Wenn Sie ein Control ändern, wird auch das Modell aktualisiert. Das Modell wiederum informiert alle damit verbun- In der API-Dokumentation wird angegeben, dass die Methode bindProperty denen Controls, dass der Wert geändert wurde. Diese Benachrichtigung löst für jede Klasse verfügbar ist, die von der übergeordneten Klasse sap.ui. ein erneutes Rendern der jeweiligen Controls aus und wird somit in allen base.ManagedObject erbt. Für zahlreiche Control-Eigenschaften, Aggregatio- Elementen widergespiegelt. nen und Assoziationen stehen auch typisierte Methoden zur Verfügung. Ob

172 173 4456.book Seite 174 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 175 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Property Binding 5.2

ein Control eine typisierte Methode für eine Eigenschaft bereitstellt, wird Beachten Sie, dass es ergänzend zur Methode bindProperty auch eine Me- durch das Kennzeichen bindable in den Metadaten des Controls festgelegt. thode unbindProperty gibt, mit der die Verbindung der Control-Eigenschaft zum Modell wieder aufgehoben wird. Wenn Sie diese Methode verwenden, Für unsere Eingabe hat das Control die Werteigenschaft aus der Klasse Input- wird der letzte in der Eigenschaft am Control festgelegte Wert beibehalten. Base geerbt. Wenn Sie die Datei InputBase.js in der Bibliothek sap.m öffnen, Er wird nicht mehr aktualisiert, wenn der Wert im Modell geändert wird. können Sie diese Zeilen im Konstruktor sehen, die die Eigenschaft value als bindable definieren (siehe Listing 5.9). Die für das Property Binding in einem JSON-Modell verwendete Logik wird in der Klasse sap.ui.model.json.JSONPropertyBinding implementiert. Ein var InputBase = Control.extend("sap.m.InputBase", / ** @lends sap.m.InputBase.prototype */ { metadata: { Großteil ihrer Funktionalität ist für alle Property Bindings in SAPUI5 verfüg- library: "sap.m", bar, da sie aus einer allgemeinen Klasse sap.ui.model.ListBinding.js ver- properties: { erbt wird. Alle Property Bindings teilen sich deshalb die Getter und Setter value: { type: "string", group: "Data", defaultValue: null, für Wert, Typ, Formatierung, externen Wert und Bindungsmodus (siehe Lis- bindable: "bindable" }, ting 5.10). [...] Listing 5.9 Auszug aus sap.m.InputBase var PropertyBinding = Binding.extend("sap.ui.model.PropertyBinding", /** @lends sap.ui.model.PropertyBinding.prototype */ { Für jede mit dem Kennzeichen bindable definierte Eigenschaft werden fol- constructor : function (oModel, sPath, oContext, mParameters) { gende Methoden automatisch erzeugt und zum Prototyp der Klasse hinzu- Binding.apply(this, arguments); gefügt: }, metadata : { ̈ get[PropertyName] "abstract" : true, ̈ set[PropertyName] publicMethods : [ "getValue", "setValue", "setType", "getType", "setFormatter", ̈ bind[PropertyName]

̈ unbind[PropertyName] "getFormatter", "getExternalValue", "setExternalValue", "getBindingMode" Für unsere Eingabe werden dadurch folgende Methoden verfügbar: ] } ̈ getValue }); ̈ setValue Listing 5.10 Vererbte Getter und Setter für Property Bindings ̈ bindValue

̈ unbindValue 5.2.2 Verwenden von Datentypen Wenn Sie das Property Binding für bestimmte Modelleigenschaften, z. B. Mit diesen Methoden werden dieselben Parameter wie für die untypisierten Float-Werte, verwenden, kann es manchmal nützlich sein, den Datentyp Varianten ermöglicht. Dies bedeutet, dass wir in den vorangehenden Bei- nicht nur dem Modell, sondern auch der Benutzeroberfläche bekannt zu ma- spielen auch die gezeigten Codezeilen hätten verwenden können: chen. Dies kann nützlich sein, wenn Sie z. B. sicherstellen möchten, dass in oInput.bindValue({ ein Textfeld nur eine Zahl für einen Preis, eine Menge oder Ähnliches bzw. path: "{/Suppliers/0/Name}" nur ein Datum für ein Geburtsdatum eingefügt wird. mode: sap.ui.model.BindingMode.OneWay }); Um dies und ein gewisses Maß an automatischer Datenformatierung, Parsen Die typisierten Funktionen sind praktische Methoden, mit denen Code einfa- und Validierung zu erreichen, können Sie Datentypen für die Bindungen in cher geschrieben und gelesen werden kann. Nicht mehr und nicht weniger! SAPUI5 verwenden.

174 175 4456.book Seite 176 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 177 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Property Binding 5.2

In SAPUI5 sind bereits einige einfache Typen verfügbar, die sofort einsatzbe- ̈ formatValue reit sind: Wenn eine Control-Eigenschaft an einen Wert im Modell gebunden wird, wird die Funktion formatValue ausgeführt, sobald eine Änderung an den ̈ sap.ui.model.type.Integer Modelldaten im Control wiedergegeben werden soll. ̈ sap.ui.model.type.Float ̈ parseValue ̈ sap.ui.model.type.String Die Funktion parseValue agiert als Formatierung in die andere Richtung. ̈ sap.ui.model.type.Boolean Sie wird ausgeführt, wenn ein Eigenschaftswert seitens der Benutzerober- ̈ sap.ui.model.type.Date fläche geändert wird und diese Änderung in das Modell zurückgegeben werden soll. ̈ sap.ui.model.type.Time ̈ validateValue ̈ sap.ui.model.type.DateTime Die Funktion validateValue wird ausgeführt, um zu ermitteln, ob Wert- Kehren wir zum Eingabebeispiel zurück. Wir können einen bestimmten Da- einschränkungen verletzt wurden. tentyp, den wir als Parameter verwenden möchten, an den Konstruktor wei- Alle Funktionen lösen entsprechende Ausnahmen aus, wenn die Anforde- tergeben (siehe Listing 5.11). rungen nicht erfüllt werden, nämlich FormatException, ParseException und new sap.m.Input({ ValidateException. value: { path:"/Suppliers/0/Address/ZipCode", Um auf diese Ausnahmen bei der Auslösung zu reagieren, müssen Sie die type: new sap.ui.model.type.Integer({ Ausnahme nicht selbst erfassen. Stattdessen sollen Sie in solchen Fällen minimum: 5, über folgende Controls an die von SAPUI5 ausgelösten Ereignisse verbin- maximum: 8 den: }) } ̈ attachFormatError }); ̈ attachParseError Listing 5.11 Festlegen eines Typs im Control-Konstruktoraufruf ̈ attachValidationError

Wir können auch den Ansatz bindProperty beibehalten und einfach den ̈ attachValidationSuccess Typ, wie in Listing 5.12 gezeigt, als einen dritten Parameter an diese Metho- Sie können problemlos auf eine falsche Benutzereingabe durch Verbinden de weitergeben. mit validationError reagieren, das z. B. ausgelöst wird, wenn die Eingabe oInput.bindProperty("value", path: "{/Suppliers/0/Name}", eines Anwenders die durch den Typ definierten Einschränkungen verletzt. new sap.ui.model.type.Integer({ minimum: 5, Betrachten wir, was geschieht, wenn wir einen Typ integer innerhalb unse- maximum: 8 rer Beispielanwendung verwenden. Der Konstruktor von sap.ui.model. }) type.Integer nutzt zwei optionale Parameter des Typobjekts – oFormat- }); Options und oConstraints. Eine neue Instanz kann somit wie folgt instanzi- Listing 5.12 Festlegen des Typs im Aufruf bindProperty am Control iert werden:

Betrachten wir nun die Details und Funktionen, wenn ein Datentyp zusam- var oType = new sap.ui.model.type.Integer(oFormatOptions, oConstraints); men mit einer Bindung verwendet wird. Jeder einfache Datentyp in SAPUI5 hat drei Funktionen: Wird einer der beiden Parameter festgelegt, werden Standardwerte für den Typ verwendet.

176 177 4456.book Seite 178 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 179 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Property Binding 5.2

Unter der folgenden Eingabe Bei jedem Fehler, der auftritt, übernimmt der verbundene Event-Handler. Wir können auf den fehlerhaften Wert zugreifen, indem wir einen Parame- var oInput = new sap.m.Input({ value: "{/Suppliers/0/Name}" ter aus dem Objekt oControlEvent verwenden, das der Event-Handler erhält. }); Bevor wir den ungültigen Wert aus der Eingabe entfernen, können wir dem oInput.placeAt("content"); Anwender einige Informationen dazu zur Verfügung stellen, was falsch ge- fügen wir eine weitere Eingabe ein, die die Postleitzahl aus der Adresse des laufen ist. Lieferanten als Wert nutzt (siehe Listing 5.13). Wir erwarten eine Eingabe Der neue Wert, den der Anwender festlegen wollte, ist als Parameter new- vom Typ integer. Value verfügbar. Ebenso können Sie auf den alten Wert, den Datentyp und var oZipInput = new sap.m.Input({ die Elemente zugreifen, für die eine Eigenschaft versucht hat, das Modell zu value: { aktualisieren. path:"/Suppliers/0/Address/ZipCode", sap.ui.model. type: new sap.ui.model.type.Integer({ Beachten Sie, dass die zusätzlichen Einschränkungen (für minimum: 1, type.Integer gibt es nur die beiden Einschränkungen, die wir verwendet maximum: 99999999 haben) nur berücksichtigt werden, wenn eine Validierung stattfindet. Diese }) erfolgt nur, wenn versucht wird, das Modell zu aktualisieren. } }); Es gibt weitere Parameter, die Sie an den Typ Integer weitergeben können. oZipInput.placeAt("content"); Diese Parameter sind allerdings Teil des Musters, das verwendet wird, wenn Listing 5.13 Verwenden eines Typs mit Einschränkungen für eine Eingabe der Quellwert eines Controls in einen String umgewandelt werden soll, da eine Control-Eigenschaft von diesem Typ ist. Dies bedeutet, dass bei jeder Beachten Sie, dass wir die Formatoptionsparameter für den Konstruktor In- Ausgabe eines Quellwerts des Typs Integer mit einer bestimmten Anzahl an teger vorläufig als leeres Objekt belassen haben. In Kürze erfahren Sie, Ziffern, z. B. in einer Werteigenschaft sap.m.Input, ein Muster angewendet wofür der Parameter am besten verwendet wird. wird, wenn der Wert in diese Control-Eigenschaft geschrieben wird, da die Eigenschaft selbst vom Typ string ist. Jetzt verbinden wir die entsprechenden Ereignisse, um den Anwendern Feedback geben zu können, wenn sie eine Falscheingabe machen (siehe Lis- Für sap.ui.model.type.Integer legen Sie z. B. die folgenden Werte fest: ting 5.14). minIntegerDigits: 1, // minimal number of non-fraction digits oZipInput.attachParseError(function(oControlEvent){ maxIntegerDigits: 99 // maximal number of non-fraction digits alert("Parse Error occurred - this is no integer"); formatOptions }); Diese Parameter sind Teil des Objekts , das wir beim ersten oZipInput.attachValidationError(function(oControlEvent){ Versuch, diesen Datentyp zu verwenden, leer gelassen haben. Wenn Sie ei- alert ("Validation error occurred - nige dieser Formatoptionen zum Beispiel hinzufügen, können Sie direkt se- some constraints were violated: " + oControlEvent.getParameters(). hen, was geschieht, wenn Sie einen Wert einfügen möchten, der nicht dem newValue + " is not between minimum and maximum"); Muster folgt. }); Listing 5.14 Verbinden mit den Validierungsereignissen aus dem Typ Legen wir z. B. einen Mindestzahl an Ziffern fest, und ändern wir das Einga- befeld für die Postleitzahl, wie es in Listing 5.15 dargestellt ist.

Wenn Sie die Anwendung neu laden und eine Zahl eingeben möchten, die var oZipInput = new sap.m.Input({ größer ist, als es in den Einschränkungen festgelegt wurde, wird ein Alert an- value: { gezeigt, dass Sie die Mindest- bzw. Maximallänge verletzt haben. Wenn Sie path:"/Suppliers/0/Address/ZipCode", nichtnumerische Zeichen eingeben, wird stattdessen ein Alert aus parse- type: new sap.ui.model.type.Integer({ minIntegerDigits: 5 Error angezeigt.

178 179 4456.book Seite 180 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 181 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Property Binding 5.2

},{ verwenden möchten. In diesem Fall ist es sinnvoll, Ihren eigenen Typ zu de- minimum: 1, finieren, da Sie ein bestimmtes Format für Telefonnummern erwarten. Da in maximum: 99999 der Beispielanwendung auch Anwendereingaben möglich sind, ist es sinn- }) } voll, die Funktion validateValue des Typs zu nutzen, um sicherzustellen, }); dass die eingegebenen Informationen die Formatanforderungen erfüllen. Listing 5.15 Festlegen der Formatoptionen für einen Typ Ansonsten wird ein Fehler ausgegeben und das bereits bekannte Ereignis va- lidationFailed ausgelöst.

Wenn Sie die Anwendung nun erneut laden und z. B. eine einstellige Zahl Erweitern wir zuerst das Modell mit der Telefonnummer für den Lieferanten einfügen möchten, wird der von Ihnen eingegebene Wert gemäß dem fest- wie in Listing 5.16 dargestellt. gelegten Muster umgewandelt, sobald das Änderungsereignis zur Eingabe ausgelöst wurde. Der einstellige Eintrag wird dann in 00001 geändert (siehe { "Suppliers": [ Abbildung 5.5). { "ID": 0, "Name": "Exotic Liquids", "Address": { "Street": "NE 228th", "City": "Sammamish", "State": "WA", "ZipCode": "98074", "Country": "USA", "PhoneNumber": "+1-123-123-1234" Abbildung 5.5 Anwendung mit Eingabe für die Postleitzahl } }, Es gibt auch mehrere Optionen für jeden der anderen Typen, und für Float- { Werte können Sie definieren, wie viele Dezimalstellen für eine Zahl zulässig "ID": 1, sind. Eine vollständige Liste der Optionen erhalten Sie im SAPUI5-Demokit "Name": "Tokyo Traders", auf der Registerkarte API Reference unter sap.ui.model.type. "Address": { "Street": "NE 40th", "City": "Redmond", 5.2.3 Definieren eines eigenen Datentyps "State": "WA", "ZipCode": "98052", Sie haben erfahren, welche wichtigen Methoden in den Datentypen in "Country": "USA", SAPUI5 enthalten sind. Nun gehen wir darauf ein, wie Sie Ihre eigenen Da- "PhoneNumber": "+1-123-123-1235" tentypen definieren können. } } Wenn Sie z. B. einen Datentyp an mehr als einer Stelle in Ihrer Anwendung ] anwenden möchten, können Sie problemlos Ihren eigenen Typ schreiben } und hierzu die Klasse sap.ui.model.SimpleType erweitern. Sie können Listing 5.16 Erweiterte JSON-Modelldaten dann Ihre spezifischen Anforderungen umsetzen, indem Sie die drei in Ab- schnitt 5.2.2, »Verwenden von Datentypen«, erläuterten Methoden imple- Im nächsten Schritt erstellen wir einen neuen Typ, indem wir die Klasse mentieren. sap.ui.model.SimpleType erweitern und die drei zuvor erwähnten Metho- den bereitstellen (siehe Listing 5.17). Sie benötigen z. B. einen speziellen Datentyp für Telefonnummern, der dem Muster +01 1234 456789 folgt, das Sie über die Anwendung hinweg wieder-

180 181 4456.book Seite 182 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 183 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Verwenden von Formatierungen 5.3

sap.ui.model.SimpleType.extend("sap.test.phoneNumber", { ")); formatValue: function(oValue) { }); return oValue; Listing 5.19 Verwenden der Validierungsausnahme, um einen Fehler für }, den Anwender auszugeben parseValue: function(oValue) { return oValue; Die Beispielanwendung sieht nun wie in Abbildung 5.6 aus. }, validateValue: function(oValue) { if (! /\+*\D*[0-9]*\-([2-9]\d{2})(\D*)([2-9]\d{2})(\D*)(\d{4}) \D/.test(oValue)) { throw new sap.ui.model.ValidateException("phone number must follow the pattern +1 234-567-890!"); } } });

Listing 5.17 Definieren eines neuen Typs Abbildung 5.6 Beispielanwendung mit hinzugefügter Telefonnummer

Lassen Sie den Wert für die ersten beiden Methoden unverändert, und ge- Wenn der Anwender jetzt etwas eingibt, das nicht dem regulären Ausdruck ben Sie diesen in der im Modell vorliegenden Form zurück. Verwenden Sie aus dem eigenen Typ entspricht, wird dem Anwender über ein Alert mitge- bei der dritten Methode einen regulären Ausdruck, um zu sehen, ob die An- teilt, dass das vordefinierte Muster nicht eingehalten wurde. wendereingabe mit dem Muster übereinstimmt, das wir für Telefonnum- mern vordefiniert haben. Verwenden von Formatierungen Wir können nun den Typ einer neuen Eingabe für die Telefonnummer in der 5.3 Beispielanwendung auf den eigenen Typ festlegen (siehe Listing 5.18). Neben dem Formatieren von Werten über Datentypen können Sie auch eige- var oPhoneInput = new sap.m.Input({ ne Formatierungen definieren, wenn Sie nicht den Wert im Modell, sondern value: { die Ausgabe in der Benutzeroberfläche beeinflussen möchten. Im Gegensatz path: "/Suppliers/0/Address/PhoneNumber", type: new sap.test.phoneNumber() zu einem Typ, der wesentlich leistungsstärker ist, ist eine Formatierung gene- } rell dort sinnvoll, wo die Formatierung eines Modells unidirektional ist. }); oPhoneInput.placeAt("content"); Wir können eine Formatierung, wie folgt, als einen Parameter an den Kon- struktor des Controls übergeben: Listing 5.18 Verwenden eines eigenen Typs oText.bindProperty("value", "/Suppliers/0/Name", function(sValue) { Schließlich verbinden wir noch mit dem Ereignis validationError. Dieses return sValue && sValue.toUpperCase(); }); Mal verwenden wir die Mitteilung aus der von uns definierten Validierungs- ausnahme, um den Anwender über den Fehler zu informieren (siehe Listing Wir können die Funktion auch weitergeben, wenn wir die Methode bind- 5.19). Property für die entsprechende Eigenschaft aufrufen (siehe Listing 5.20).

oPhoneInput.attachValidationError(function(oControlEvent){ oText = new sap.m.Text ({ alert ("Validation error occurred - value: { constraints were violated: " + oControlEvent.getParameter("message path: "/Suppliers/0/Name", formatter: function(sValue) { return sValue && sValue.toUpperCase();

182 183 4456.book Seite 184 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 185 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Verwenden von Formatierungen 5.3

} } /* ======*/ }) /* lifecycle methods */ Listing 5.20 Einsatz einer Formatierung für sap.m.Text Control /* ======*/

/** Beachten Sie, dass in beiden Fällen die Formatierungsfunktion eine anony- * Called when the worklist controller is instantiated. me Callback-Funktion ist, die ausgeführt wird, wenn der View instanziiert * @public wird. */ onInit: function() { Sie können eine Formatierungsfunktion auch nicht anonym in einem View- this.getRouter().getRoute("detail").attachPatternMatched(this Controller definieren. Bei einer Wiederverwendung über die Anwendung ._onObjectMatched, this); hinweg kann es sogar sinnvoll sein, eine separate Datei formatter.js in der }, Anwendung verfügbar zu haben, die in mehreren Views referenziert werden /* ======*/ kann. /* event handlers */ Im ersten Fall müssen Sie die Funktion nur im Controller, wie in Listing 5.21 /* ======*/ dargestellt, implementieren. /** onInit: function(){ * Navigates back to the Master [...] * @function }, */ onExit: function(){ onNavPress: function() { [...] this.myNavBack("master"); } }, toUpperCase: function(sName){ return sName && sName.toUpperCase(); /* ======*/ } /* formatters */ /* ======*/ Listing 5.21 Code der Formatierung im Controller

/** Anstelle der anonymen Funktion aus dem vorangehenden Beispiel können * Formats a given string to uppercase. Sie dann diese Formatierung wie folgt verwenden: * * @function oText.bindProperty("value", "/Suppliers/0/Name", toUpperCase); * @param {string} sName string to be formatted Zurück in unserer MVC-Anwendung können wir auch die Formatierung nut- * @public */ zen, indem wir sie von Listing 5.21 in den Controller des Detail-Views über- toUpperCase: function(sName) { tragen. Fügen Sie die Zeilen aus Listing 5.21 in die Datei Detail.controller.js return sName && sName.toUpperCase(); ein. Der Detail-Controller sieht nun wie in Listing 5.22 aus. },

sap.ui.define([ /* ======*/ "sapui5/demo/mvcapp/controller/BaseController" /* internal methods */ ], function(BaseController) { /* ======*/ "use strict";

/** return BaseController.extend("sapui5.demo.mvcapp.controller.Detai * Binds the view to the object path. l", {

184 185 4456.book Seite 186 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 187 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Verwenden von Formatierungen 5.3

* * @param {sap.ui.base.Event} oEvent pattern match event * in route 'object' * @private */ _onObjectMatched: function(oEvent) { var sObjectPath = "/Suppliers/ Listing 5.23 Detail-View in der MVC-Anwendung " + oEvent.getParameter("arguments").ID; this._bindView(sObjectPath); . }, Mit dem Punkt ( ) vor dem Namen der Formatierungsfunktion wird dem Framework mitgeteilt, dass es innerhalb des aktuellen Controllers nach einer /** Formatierung suchen soll. * Binds the view to the object path. * Durch das Ausführen der Anwendung und Laden der Details eines Lieferan- * @function ten wird ein Bildschirm wie in Abbildung 5.7 erzeugt. Dort sehen Sie, dass * @param {string} sObjectPath path to the object to be bound der Lieferantenname jetzt in Großbuchstaben angezeigt wird. Der Wert des * @private Modells bleibt von dieser Änderung unberührt. */ _bindView: function(sObjectPath) { var oView = this.getView(); oView.bindElement(sObjectPath); } }); }); Listing 5.22 Detail-Controller in der MVC-Anwendung

Im Detail-View können wir nun die Formatierung, wie in Listing 5.23 ge- zeigt, nutzen. Abbildung 5.7 Detail-View mit der Formatierung in Aktion tierungsfunktionen in eine separate Datei übertragen, die über die Anwen- ner model ab, da sie zu einer Funktionalität gehört, die sich auf das Modell return {

186 187 4456.book Seite 188 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 189 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Verwenden von Formatierungen 5.3

/*======*/ /** /* event handlers */ * Formats a given string to uppercase. /* ======*/ * * @function /** * @param {string} sName string to be formatted * Navigates back to the Master * @public * @function */ */ toUpperCase: function(sName) { onNavPress: function() { return sName && sName.toUpperCase(); this.myNavBack("master"); } }, }; /* ======*/ }); /* internal methods */ Listing 5.24 formatter.js für die MVC-Anwendung /* ======*/

/** Wird diese Formatierung aus einem Controller geladen, gibt sie ein Ob- * Binds the view to the object path. jekt mit der Funktion toUpperCase zurück, die als Member-Funktion ver- * fügbar ist. * @function * @param {sap.ui.base.Event} oEvent pattern match event in Wir stellen nun sicher, dass den Controllern diese zusätzliche Funktion be- * route 'object' kannt ist, indem wir diese in die Controller-Definition des Detail-Views ein- * @private fügen. Der Controller sieht jetzt wie in Listing 5.25 aus. */ _onObjectMatched: function(oEvent) { sap.ui.define([ var sObjectPath = "/Suppliers/ "sapui5/demo/mvcapp/controller/BaseController", " + oEvent.getParameter("arguments").ID; "sapui5/demo/mvcapp/model/formatter" this._bindView(sObjectPath); ], function(BaseController, formatter) { }, "use strict"; return BaseController.extend("sapui5.demo.mvcapp.controller.Detai /** l", { * Binds the view to the object path. * formatter: formatter, * @function /* ======*/ * @param {string} sObjectPath path to the object to be bound /* lifecycle methods */ * @private /* ======*/ */ _bindView: function(sObjectPath) { /** var oView = this.getView(); * Called when the worklist controller is instantiated. oView.bindElement(sObjectPath); * @public } */ }); onInit: function() { }); this.getRouter().getRoute("detail").attachPatternMatched Listing 5.25 Einfügen der Formatierung in den Controller (this._onObjectMatched, this); }, Beachten Sie, dass innerhalb des Controllers die entsprechende Formatie- rungsfunktion gelöscht wurde.

188 189 4456.book Seite 190 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 191 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Verwenden von Formatierungen 5.3

Im View muss der Zugriff auf die Formatierung nun etwas anders erfolgen. sap.ui.define([ Wie erwähnt, laden wir die Formatierungsdatei und übergeben das zurück- "sap/ui/model/SimpleType" ], function (SimpleType) { gegebene Objekt als Parameter an den Controller. Die Formatierung ist dann "use strict"; als Eigenschaft formatter im Controller verfügbar. Wir müssen deshalb Ob- return { jectHeader in der Datei Detail.view.xml ändern, in der wir die Formatierung, wie in Listing 5.26 dargestellt, verwenden möchten. /** * Data Type for phone numbers. }, return oValue; }, validateValue: function(oValue) { Listing 5.26 Auszug aus Detail.view.xml if (!/\+*\D*[0-9]*\-([2-9]\d{2})(\D*)([2-9]\d{2})(\D*) (\d{4})\D/.test(oValue)) { throw new sap.ui.model.ValidateException("phone number Wenn alles ordnungsgemäß ausgeführt wurde, wird nach dem erneuten La- must follow the pattern +1 234-567-890!"); den der Anwendung dasselbe Ergebnis im Browser angezeigt. Wir haben } nichts an der Art der Formatierung geändert, sondern nur die Wiederver- } wendbarkeit verbessert, indem wir den Formatter an einem anderen Ort ge- }) speichert haben. Wir könnten diese jetzt in mehrere Controller in unserer }; Anwendung einfügen. }); Listing 5.27 Separate Datei types.js, die in der Anwendung verwendet werden soll Wir zeigen nun weitere Informationen über unseren Lieferanten an und fü- gen hierzu einige zusätzliche Felder zum Objekt-Header im Detail-View hin- Als Nächstes müssen wir das Modell in dieser Anwendung ein wenig erwei- zu. Wir möchten die Adresse und die Telefonnummer eines Lieferanten mit tern, wie wir es bereits in der kleineren Beispielanwendung umgesetzt ha- dem Datentyp aus dem vorangehenden Beispiel für die Telefonnummer ein- ben. Dies ermöglicht, dass die Informationen angezeigt werden können. Die fügen. Datei model.json sieht jetzt wie in Listing 5.28 aus.

Erstellen Sie eine Datei types.js, die der Datei formatters.js ähnlich ist, inner- { halb des Verzeichnisses model der MVC-Anwendung, kopieren Sie den Datei- "Suppliers":[ typ für die Telefonnummer aus Abschnitt 5.2.3, »Definieren eines eigenen { Datentyps«, und fügen Sie diesen ein. Wir verwenden wieder die Syntax de- "ID":0, "Name":"Exotic Liquids", fine und sorgen dafür, dass das Modul ein Objekt mit spezifischen Typen als "Address":{ Eigenschaften zurückgibt. "Street":"NE 228th", "City":"Sammamish", Der vollständige Code innerhalb der Datei types.js sieht wie in Listing 5.27 "State":"WA", aus. "ZipCode":"98074", "Country":"USA",

190 191 4456.book Seite 192 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 193 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Aggregation Binding 5.4

"PhoneNumber": "+1-123-123-1234" Führen Sie die Anwendung aus, und wählen Sie einen Lieferanten aus der }, Liste aus. Der Bildschirm sollte wie in Abbildung 5.8 aussehen. [...] ,{ "ID":1, "Name":"Tokyo Traders", "Address":{ "Street":"NE 40th", "City":"Redmond", "State":"WA", "ZipCode":"98052", "Country":"USA" "PhoneNumber": "+1-123-123-1235" }, [...] } Abbildung 5.8 Detail-View mit Typ für die Telefonnummer Listing 5.28 Modellauszug – Telefonnummer zu den Lieferanten hinzugefügt

Nun müssen wir dem Controller erneut mitteilen, wo der im View zu ver- 5.4 Aggregation Binding wendende Typ vorliegt. Wie bei der Formatierung fügen Sie die Typen ein- fach den Modulen hinzu, die im Abschnitt define des Controllers geladen Bisher haben wir die Property Bindings in der Anwendung betrachtet. Es wurden (siehe Listing 5.29). gibt aber einen weiteren Binding-Typ namens Aggregation Binding, mit dem

sap.ui.define([ Elemente für eine Control-Aggregation aus den Modelldaten automatisch er- "sapui5/demo/mvcapp/controller/BaseController", zeugt werden. "sapui5/demo/mvcapp/model/formatter", "sapui5/demo/mvcapp/model/types" Ein Beispiel hierzu finden wir in Master.view.xml (siehe Listing 5.30). ], function (BaseController, formatter, types) {

Listing 5.29 Auszug aus Detail.controller.js [...] zusätzliche Objektattribut, wie gezeigt, zum View hinzu: path: 'Address/PhoneNumber', }" />

192 193 4456.book Seite 194 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 195 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Aggregation Binding 5.4

} }); Listing 5.30 Auszug aus dem Master-View mit Aggregation Binding Listing 5.31 Aggregation Binding in JavaScript

Die Elementaggregation für die Tabelle wird automatisch mit einem Element Innerhalb des XML-Views ist diese Vorlage deklarativ innerhalb der Aggre- pro Modellknoten befüllt, der durch den im Elementattribut in Listing 5.30 gationsgrenzen festgelegt. vergebenen Pfad referenziert wurde. Für jedes Element muss eine Vorlage Einige Controls bieten eine Standardaggregation, die Sie aus den Metadaten angewendet werden. Diese Vorlage wird dann für jeden Wert im Modell ge- des Controls in der entsprechenden Control-Klasse identifizieren können. klont, und der Bindungspfad des aggregierten Elements wird auf den ent- Wenn Sie sap.m.ObjectHeader in der Beispielanwendung betrachten, sind sprechenden Modellknoten festgelegt. die folgenden Zeilen in den Metadaten fett markiert (siehe Listing 5.32): Verwenden Sie, wie in Kapitel 4, »Aufbau von MVC-Anwendungen«, er- [Property definitions here...] wähnt, den in Listing 5.31 dargestellten Code, wenn Sie das übergeordnete }, Control innerhalb eines JavaScript-Views instanziieren und die Aggregation- defaultAggregation : "attributes", Binding-Parameter direkt an den Control-Konstruktor übergeben möchten. aggregations : { [Aggregation definitions follow here...] var aColumns = [ Listing 5.32 In den Metadaten eines Controls definierte Standardaggregation new sap.m.Column({ header: new sap.m.Text({ text: "ID" Diese Standardaggregationen werden automatisch eingesetzt, wenn Sie die }) Aggregation nicht innerhalb eines XML-Views festlegen (siehe Listing 5.33). }), new sap.m.Column({ var oTemplate = new sap.m.ColumnListItem({ cells: [ new sap.m.ObjectIdentifier({ text: "{Name}" Listing 5.33 Auszug aus Detail.view.xml ohne explizite Nutzung der Standardaggregation }) ] Über den Code aus Listing 5.33 und dem folgenden Listing 5.34 wird das- }); selbe DOM erzeugt, selbst wenn Letzteres zusätzliche Tags zum Öffnen und var oTable = new sap.m.Table({ Schließen der Standardaggregation enthält: columns: aColumns,

194 195 4456.book Seite 196 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 197 Mittwoch, 9. November 2016 10:03 10

5 Modelle und Bindings Aggregation Binding 5.4

}"

number="ID: {ID}">
type: '.types.PhoneNumber' }" />
Listing 5.34 Auszug aus Detail.view.xml mit expliziter Nutzung der Standardaggregation
Üblicherweise wird der Inhalt der Standardaggregationen im XML-View ohne die umgebenden Tags eingefügt, die normalerweise den Beginn und das Ende einer Aggregation anzeigen. Die »Begrenzungs-Tags« müssen nur für diejenigen Aggregationen explizit angegeben werden, die nicht als Stan- dard für das Eltern-Control definiert sind. Beachten Sie, dass innerhalb eines Aggregation Bindings erstellte Controls am Lebenszyklus der übergeordneten Elemente beteiligt sind. Sie werden in- stanziiert, wenn die übergeordneten Controls instanziiert werden, und ge- meinsam mit den übergeordneten Elementen zerstört.
Wir erweitern unsere Beispielanwendung um ein weiteres Aggregation Bin- Listing 5.35 Produkttabelle im Detail-View ding im Detail-View, indem wir ein weiteres Control sap.m.Table hinzu- fügen, das alle von einem bestimmten Lieferanten angebotenen Produkte Wenn Sie diese Aggregation hinzufügen, wird ein Element für jedes mit dem enthält. Lieferanten im Modell assoziierte Produkt instanziiert. Die Anwendung soll- te jetzt wie in Abbildung 5.9 aussehen. Diese Tabelle fügen wir zur Datei Detail.view.xml direkt unter dem schließen- den Tag hinzu (siehe Listing 5.35).

</Toolbar> </headerToolbar> <columns> <Column id="idColumn"> Abbildung 5.9 Detail-View mit Produkten</p><p>196 197 4456.book Seite 198 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 199 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Aggregation Binding 5.4</p><p>5.4.1 bindAggregation Zuerst erweitern wir das JSON-Modell, um diese Informationen wiederzuge- Anstatt die Aggregationsvorlage zu deklarieren und innerhalb des XML- ben, entfernen dann das deklarative Aggregation Binding innerhalb unseres Views zu binden, können wir die entsprechende Methode auf dem überge- Views und setzen stattdessen die Produktaggregation programmatisch um, ordneten Control, d. h. der Funktion bindAggregation, verwenden. Diese die wir im Controller anzeigen lassen möchten (siehe Listing 5.36). Methode kann wie die Methode bindProperty eingesetzt werden, wenn Sie { die gewünschte Aggregation nicht bei der Instanziierung des übergeordne- "Suppliers": [{ ten Controls, sondern zu einem späteren Zeitpunkt im Code verwenden "ID": 0, "Name": "Exotic Liquids", möchten. "Address": { Diese Funktion enthält zwei Parameter: den Namen der Aggregation und ein "Street": "NE 228th", "City": "Sammamish", Objekt oBindingInfo. Dieses Objekt selbst kann mehrere Parameter umfas- "State": "WA", sen. Einige davon betrachten wir in den folgenden Unterabschnitten. "ZipCode": "98074", "Country": "USA", Hinsichtlich der Methode bindProperty bieten einige Controls typisierte "Phone Number":"001555789789789" Methoden für das Aggregation Binding an. In den Metadaten des Controls werden diese Methoden durch das Kennzeichen bindable bei der Aggrega- }, tionsdefinition bestimmt. Beachten Sie, dass die Methoden durch die über- "Location": { geordnete Klasse sap.ui.base.ManagedObject automatisch erzeugt werden, "type": "Point", "coordinates": [-122.03547668457, jedoch beim spezifischen Control übersteuert werden können. 47.6316604614258 Im Fall von sap.m.Table aus dem vorangehenden Beispiel wäre folgender ] }, Aufruf möglich gewesen: "Products": [{ oTable.bindItems("Products", oBindingInfo); "ID": 1, "Name": "Milk", Ergänzend zur Methode bindAggregation gibt es auch eine Methode unbind- "Description": "Low fat milk", Aggregation, die analog zur bereits bekannten Methode unbindProperty ist. "ReleaseDate": "1995-10-01T00:00:00", "DiscontinuedDate": null, "Rating": 3, 5.4.2 Verwenden einer Factory "Price": 3.5 }, { Ein großer Vorteil des Programmieransatzes ist, dass Sie eine Factory zusam- "ID": 2, men mit der Funktion bindAggregation verwenden können. Ein häufiger "Name": "Vint soda", Anwendungsfall ist die dynamische Erstellung der Benutzeroberfläche, z. B. "Description": "Americana Variety - Mix of 6 flavors", wenn Sie zusätzliche oder andere untergeordnete Controls anzeigen lassen "ReleaseDate": "2000-10-01T00:00:00", möchten, falls bestimmte Kriterien erfüllt werden. "DiscontinuedDate": null, "Rating": 3, Angenommen, wir möchten in unserer Anwendung nicht alle Produkte "Price": 20.9 gleich anzeigen lassen und die Anzeige für die Produkte mit bestimmten }, { "ID": 3, Zutaten anpassen. Dieser Teil der Übung weicht ein wenig vom Pfad ab, den "Name": "Havina Cola", die Beispielanwendung für das restliche Kapitel nehmen wird. Stellen Sie "Description": "The Original Key Lime Cola", also sicher, dass Sie eine Kopie Ihrer Arbeit speichern, bevor Sie die nächsten "ReleaseDate": "2005-10-01T00:00:00", Schritte durchführen. Wir kehren nach diesem Abschnitt zum eigentlichen "DiscontinuedDate": "2006-10-01T00:00:00", Beispiel zurück. "Rating": 3,</p><p>198 199 4456.book Seite 200 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 201 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Aggregation Binding 5.4</p><p>"Price": 19.9 fügen wir ein Control zur Elementliste hinzu, wenn diese Information im }, { Modell enthalten ist. "ID": 4, "Name": "Fruit Punch", Wir entfernen zunächst einen Teil der Tabellendefinition aus dem vorange- "Description": "Mango flavor, 8.3 Ounce Cans (Pack of 24)", henden Beispiel, sodass der Detail-View jetzt wie in Listing 5.37 aussieht. "ReleaseDate": "2003-01-05T00:00:00", "DiscontinuedDate": null, <mvc:View controllerName= "Rating": 3, "sapui5.demo.mvcapp.controller.Detail" xmlns:mvc= "Price": 22.99 "sap.ui.core.mvc" xmlns="sap.m"> }, { <Page id="page" navButtonPress="onNavPress" showNavButton= "ID": 5, "true" title="Supplier Details"> "Name": "Cranberry Juice", <content> "Description": "16-Ounce Plastic Bottles (Pack of 12)", <ObjectHeader id="objectHeader" title="{ "ReleaseDate": "2006-08-04T00:00:00", path: 'Name', "DiscontinuedDate": null, formatter: '.formatter.formatUpperCase' "Rating": 3, }" number="ID: {ID}"> "Price": 22.8 <attributes> }, { <ObjectAttribute text="{Address/Country}"> "ID": 6, </ObjectAttribute> "Name": "Pink Lemonade", <ObjectAttribute text="{ "Description": "36 Ounce Cans (Pack of 3)", path: 'Address/PhoneNumber', "ReleaseDate": "2006-11-05T00:00:00", type: '.types.PhoneNumber' "DiscontinuedDate": null, }" /> "Allergens": "Milk, Soy, Edible Nuts, Gluten", </attributes> "Rating": 3, </ObjectHeader> "Price": 18.8 <Table id="table" width="auto" class= }] "sapUiResponsiveMargin" noDataText="No Data" growing= }, { "true" growingScrollToLoad="true"> "ID": 7, <headerToolbar> "Name": "Green Lemonade", <Toolbar> "Description": "36 Ounce Cans (Pack of 3)", <Title id="tableHeader" text="Suppliers Products" /> "ReleaseDate": "2006-11-05T00:00:00", </Toolbar> "DiscontinuedDate": null, </headerToolbar> "Allergens": "Milk, Soy, Edible Nuts, Gluten", <columns> "Rating": 3, <Column id="idColumn"> "Price": 18.8 <header> }] <Text text="ID:" id="IDColumnTitle" /> }, </header> </Column> [...] <Column id="nameColumn"> ] <header> } <Text text="Name:" id="nameColumnTitle" /> Listing 5.36 Geändertes JSON-Modell, um zusätzliche Produktinformationen anzuzeigen </header> </Column> <Column id="priceColumn" hAlign="Right"> Einige Produkte wurden um Informationen über enthaltene Allergene erwei- <header> tert. Um diese Informationen deutlich in der Produktliste hervorzuheben, <Text text="Price:" id="priceColumnTitle" /></p><p>200 201 4456.book Seite 202 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 203 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Aggregation Binding 5.4</p><p></header> new sap.m.Text({ </Column> text: "{Allergens}" </columns> }) </Table> ] </content> })); </Page> } else { </mvc:View> // no allergens there, we display the name as usual Listing 5.37 Detail-View ohne Elementaggregation für die Tabelle oColumnListItem.addCell(new sap.m.ObjectIdentifier({ text: "{Name}" })); Wenn Sie die Anwendung nun im Browser neu laden, wird die Tabelle wei- } terhin angezeigt. Allerdings werden keine Einzelposten angezeigt, sondern nur noDataText. oColumnListItem.addCell(new sap.m.ObjectNumber({ number: "{Price}", In der Funktion _onObjectMatched im Detail-Controller rufen wir nun wie unit: "USD" folgt eine weitere private Funktion auf: })); return oColumnListItem; createProductsAggregation(sObjectPath); }); Danach müssen wir diese Funktion implementieren, mit der die Element- } aggregation in der Tabelle erstellt wird. In dieser Funktion möchten wir ein Listing 5.38 Binden der Elementaggregation mit einer Factory bestimmtes Control verwenden, nämlich VerticalLayout aus der Bibliothek sap.ui.layout. Wir müssen sicherstellen, dass dieses Control dem Control- Sie können im Code erkennen, dass wir nun die Controls innerhalb der Ag- ler bekannt ist. Daher fügen wir es in den define-Teil des Controllers ein gregation instanziieren, indem wir eine Factory-Funktion an die Methode (siehe Listing 5.38). bindAggregation weitergeben, die wir im übergeordneten Control aufrufen. Wird das übergeordnete Control nun instanziiert und die Aggregation er- _createProductsAggregation: function() { stellt, wird die Factory für jeden Eintrag im Modell ausgeführt. Abhängig da- var oTable = this.getView().byId("table"); von, ob ein Produkt ein Allergen enthält, wird entweder nur der Name des oTable.bindAggregation("items", "Products", function(sId, Produkts angezeigt oder eine Spalte mit dem Control-Typ sap.ui.lay- oContext) { out.VerticalLayout erstellt, mit der wir mehr als ein Inhalts-Control für das var sAllergens = oContext.getProperty("Allergens"); vertikale Layout festlegen können. var oColumnListItem = new sap.m.ColumnListItem(sId); oColumnListItem.addCell(new sap.m.ObjectIdentifier({ Wir verwenden dann einfach zwei Text-Control, die beide in die Content- text: "{ID}" Aggregation von VerticalLayout einfließen. So wird die Leistungsfähigkeit })); beim Einsatz von Factorys im Aggregation Binding deutlich, da Sie als Ent-</p><p> if (sAllergens) { wickler entscheiden können, ob Sie dieselben Informationen, abhängig von // we have found allergens, so we provide a VerticalLayout den Daten, in unterschiedlicher Form anzeigen lassen oder sogar ein voll- // instead of just displaying the product name. The ständiges Control durch ein anderes Control ersetzen möchten. // VerticalLayout then takes the product name plus the // allergens into its own content aggregation Wenn Sie die Seite neu laden, können Sie sehen, dass es Produkte mit zusätz- oColumnListItem.addCell(new VerticalLayout({ lichen Informationen innerhalb eines anderen Controls in der Zelle mit der content: [ Beschreibung gibt, während andere Produkte ohne zusätzliche Informatio- new sap.m.Text({ nen angezeigt werden. text: "{Name}" }),</p><p>202 203 4456.book Seite 204 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 205 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Element Binding 5.5</p><p>Die über die Factory für die Aggregation erzeugten Controls verhalten sich Innerhalb des Detail-Views gibt es einige Property Bindings, die immer die wie jedes andere Aggregationselement. Dies bedeutet, dass sie Teil des Le- Informationen über den ausgewählten Lieferanten anzeigen. Dies gilt auch benszyklus des übergeordneten Elements sind. Mit den neu hinzugefügten für sap.m.List, für die wir unsere Elementaggregation definiert haben, da- Elementen sollte der Detail-View der Anwendung wie in Abbildung 5.10 mit die Produkte eines bestimmten Lieferanten angezeigt werden. Keiner aussehen. dieser Pfade beginnt mit einem Schrägstrich, was darauf hinweist, dass uns ein relativer Bindungspfad vorliegt.</p><p>Ermitteln wir nun, woher die Informationen darüber kommen, wie diese Pfade aufgelöst werden: Wenn Sie den Code, der den Detail-Controller in- stanziiert, etwas genauer betrachten, sehen Sie ein in der Methode verwen- detes Element Binding, in dem das Ereignis patternMatched verarbeitet wird (siehe Listing 5.39).</p><p>_onObjectMatched : function (oEvent) { var sObjectPath = "/Suppliers/ " + oEvent.getParameter("arguments").ID; this._bindView(sObjectPath); },</p><p>_bindView : function (sObjectPath) { var oView = this.getView(); oView.bindElement(sObjectPath); } Listing 5.39 Binden eines Views an ein Element</p><p>Wird ein Lieferant im Master-View angeklickt, werden die Informationen zur Lieferanten-ID über ein Routing an den Detail-View weitergegeben. Der Abbildung 5.10 Produkte des Lieferanten mit Informationen über Allergene Parameter ist dann in dem Ereignis verfügbar, das an den entsprechenden Event-Handler übergeben wird.</p><p>5.5 Element Binding Wir können somit durch Zusammenbringen der Pfadinformationen bestim- men, welcher Lieferant im Detail-View angezeigt werden soll. Hierzu wird Sie haben gesehen, dass die Informationen, die beim Umschalten vom Mas- innerhalb des Ereignisses onObjectMatched der Name der Sammlung im Mo- ter- auf den Detail-View angezeigt werden, davon abhängen, welchen Liefe- dell mit der ID aus dem Ereignisparameter kombiniert. ranten wir aus der Tabelle ausgewählt haben. Im Aggregation Binding haben wir den relativen Bindungspfad zu den Produkten verwendet. Um diesen re- Als Nächstes nutzen wir diese Informationen innerhalb unserer privaten Me- lativen Bindungspfad an den ausgewählten Lieferanten anzupassen, muss thode _bindView, in der wir bindElement explizit im View aufrufen. Über die dem übergeordneten Element des Controls List, das die Aggregation ent- Funktion bindElement wird dann ein Bindungskontext für ein SAPUI5-Con- hält, mitgeteilt werden, wie dieser Pfad korrekt aufgelöst wird. Hierzu ver- trol erstellt und der Modellname sowie der Pfad zu einem Element in einem wenden wir einen dritten Bindungstyp: Element Binding. Konfigurationsobjekt empfangen. Dies löst eine Aktualisierung der UI-Con- trols aus, die wir mit den Modellfeldern verbunden haben. Ein Element Binding ermöglicht es uns, einen Kontext für alle relativen Bin- dungen innerhalb eines Elements zu erstellen. Wir möchten dies anhand eines Beispiels verdeutlichen.</p><p>204 205 4456.book Seite 206 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 207 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Expression Binding und berechnete Felder 5.6</p><p>Wird das Element Binding in einen anderen Bindungskontext gesetzt, z. B. <ObjectAttribute wenn wir zu einem anderen Lieferanten wechseln, werden alle Controls in- text="{Address/City}, {Address/Country}"> </ObjectAttribute> nerhalb des Views mit den entsprechenden Werten aktualisiert. <ObjectAttribute Die Funktion bindElement wird aus der Klasse sap.ui.base.Element vererbt text="{ path: 'Address/PhoneNumber', und kann in jedem untergeordneten Element aufgerufen werden. Wie bei type: '.types.PhoneNumber' unbindElement den anderen Bindungstypen gibt es auch eine Funktion , mit }" /> der ein bestimmter, für ein Element erstellter Bindungskontext entfernt wer- </attributes> den kann. </ObjectHeader> Listing 5.40 Objekt-Header im Detail-View</p><p>5.6 Expression Binding und berechnete Felder Wir geben einfach zwei Werte an den Detail-View weiter, woraufhin in SAPUI5 eine automatische Verkettung der beiden Werte stattfindet. Im Sie haben erfahren, wie Werte aus den Modellen für unterschiedliche Bin- Framework wird automatisch ein Composite Binding erstellt, und mit die- dungstypen verwendet und wie diese entweder über Formatierungsfunktio- sem Composite Binding werden die Daten kombiniert und in der Benutzer- nen oder einen Datentyp formatiert werden. Bisher haben wir allerdings mit oberfläche bereitgestellt. jeweils nur einem Wert gearbeitet. Wenn Sie die Seite jetzt neu laden, wird dadurch das berechnete Feld, wie in Wie kombinieren wir aber mehrere Werte aus dem Modell in einer Control- Abbildung 5.11 dargestellt, angezeigt. Eigenschaft? Hier kommen dann Expression Bindings oder berechnete Felder ins Spiel. Wir kombinieren nun einige der Lieferanteninformationen im De- tail-View an einem Ort. Hierzu verwenden wir die Stadt und den Bundes- staat als Beispiel.</p><p>5.6.1 Berechnete Felder Berechnete Felder können an die Eigenschaft weitergegeben werden, die Sie, ähnlich wie die herkömmliche Bindung, binden möchten. Der einzige Unter- Abbildung 5.11 Objekt-Header – berechnetes Feld schied ist, dass Sie nun mehr als einen Teil des Werts übergeben müssen, weshalb Sie diese bei der Implementierung als genau solche festlegen kön- Möchten Sie diese Art der Bindung innerhalb des JavaScript-Codes verwen- nen: als Teile. den, müssen Sie die Teile der Bindung, wie in Listing 5.41 gezeigt, explizit Im Detail-View ändern wir ObjectHeader mit den in Listing 5.40 gezeigten festlegen. Lieferanteninformationen. var oObjectHeaderAttribute = new sap.m.ObjectAttribute({ text: { <ObjectHeader parts: [ id="objectHeader" {path: "Address/ title="{ City", type: new sap.ui.model.type.String()}, path: 'Name', {path: "Address/Country"} formatter: '.formatter.formatUpperCase' ] }" } number="ID: {ID}"> }); <attributes> Listing 5.41 Erstellen eines Objekt-Headers</p><p>206 207 4456.book Seite 208 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 209 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Expression Binding und berechnete Felder 5.6</p><p>Sie können für jeden Pfad einen anderen Typ bestimmen. Dies ist jedoch 5.6.2 Expression Binding nicht obligatorisch. In diesem Fall müssen Sie sich allerdings selbst um die Expression Binding ist eine weitere Data-Binding-Funktion in SAPUI5, die Formatierung kümmern, weshalb Sie hier auch eine eigene Formatierung anstelle einer Formatierung verwendet werden kann, wenn die Bindung auf einreichen können. Ansonsten wird vom Framework der standardmäßige bestimmten Bedingungen basieren muss. Wenn Sie eine ziemlich einfache Verkettungsmechanismus verwendet, bei dem die beiden Strings einfach Formatierung programmieren, mit der lediglich zwei Werte verglichen wer- miteinander kombiniert werden. den, sollten Sie darüber nachdenken, ob ein Expression Binding nicht auch Die Übergabe einer Formatierung ist einfach. Sie können sie einfach inner- ausreichend wäre. halb eines Objektliterals wie in Listing 5.42 oder als Parameter in der (typi- Sie könnten den Code aus der Factory in Abschnitt 5.4.2, »Verwenden einer bindProperty sierten oder untypisierten) Methode am Control übergeben. Factory«, umschreiben und einen Ausdruck verwenden, um zu bestimmen, oObjectHeaderAttribute.bindText({ ob das Text-Control mit den Allergenen für ein Produkt angezeigt werden parts: [ soll oder nicht. In diesem Fall müssten Sie nur den View ein wenig ändern, {path: "Address/City", type: new sap.ui.model.type.String()}, statt den Controller zu erweitern. Der Elementteil im Detail-View würde {path: "Address/Country"} dann wie in Listing 5.43 aussehen. ] }, <items> formatter: function(sCity, sCountry){ <ColumnListItem> if (sCity && sCountry) { <cells> return sCity + ", " + sCountry; <ObjectIdentifier } text="{ID}"/> }); <layout:VerticalLayout> Listing 5.42 Übergeben der Formatierung an die Bindungsmethode <Text text="{Name}"/> <Text text="{Allergenics}" visible="{= ${Allergenics} !== '' }"/> Sie können beliebig viele Werte in einer berechneten Bindung kombinieren, </layout:VerticalLayout> und Sie müssen sich nur über die Art der Verkettung kümmern, die inner- <ObjectNumber halb dieser Funktion zum Einsatz kommen soll. Wird das Layout jedoch number="{Price}" komplexer, möchten Sie möglicherweise auf mehr als ein Control zurück- unit="USD" /> greifen, meist in Kombination mit einem SAPUI5-Layout-Control. Versuchen </cells> </ColumnListItem> Sie nicht, hier HTML-Code auszugeben. Dieser ist schwierig zu formatieren </items> und kann sogar die Struktur Ihrer Seite zerstören. Listing 5.43 Verwenden eines Expression Bindings anstelle einer Formatierung Unidirektionale Verwendung berechneter Felder Das Expression Binding wird nur empfohlen, wenn die Ausdrücke nicht Wenn Sie berechnete Felder verwenden, müssen Sie sich bewusst sein, dass dies übermäßig komplex sind. Der Nachteil dieses Ansatzes ist, dass das vertikale nur unidirektional funktioniert. Aktuell gibt es keinen Mechanismus, der eine bidi- rektionale Bindung für solche Felder erlaubt, da der Algorithmus, mit dem die Layout weiterhin als solches gerendert würde, selbst wenn eines der darin potenziellen Anwendungsfälle für die Rückwärtsberechnung berechnet würde, so enthaltenen Controls nicht sichtbar wäre und somit das DOM mit unnötigen komplex wäre, dass das Framework diesen nicht mehr implementieren könnte. Elementen belasten würde. Bei komplexeren Anwendungsfällen sind die an- deren von uns erläuterten Implementierungsoptionen – Formatierungen Wenn Sie den Anwendern die Möglichkeit geben möchten, den Wert einer oder Factorys für Aggregation Bindings – möglicherweise besser geeignet. Eingabe mit einem berechneten Feld zu ändern, müssen Sie die Logik imple- mentieren, die diese Änderungen im Modell selbst wiedergeben kann.</p><p>208 209 4456.book Seite 210 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 211 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Ressourcenmodelle und Internationalisierung 5.7</p><p>Sie können verschiedene Operatoren innerhalb von Ausdrücken einsetzen – enthält, deren Sprache durch Gebietsschemabezeichner im Dateinamen be- u. a. Equality-Operatoren, Multiplication-Operatoren und additive Operato- stimmt werden. In Tabelle 5.1 werden einige Beispiele für Ressourcenbün- ren. Im SAPUI5-Demokit auf der Registerkarte API Reference finden Sie del-Dateien aufgeführt. weitere Informationen. Dateiname Beschreibung</p><p> i18n.properties Es ist keine Sprache definiert. Daher wird die Standardspra- 5.7 Ressourcenmodelle und Internationalisierung che vorausgesetzt. Welche Sprache genau als Standard gilt, wird durch den größeren Kontext bestimmt, in dem Ihre Anwendung ausgeführt wird. Ein Ressourcenmodell ist eine Sonderform des clientseitigen Modells, das für Wenn z. B. die Standardsprache im Unternehmen Englisch die Internationalisierung in SAPUI5 verwendet wird. Es agiert als Wrapper ist, sind die in dieser Datei enthaltenen Texte englischspra- für Ressourcenbündel. Ein Ressourcenbündel ist eine Datei zum Speichern chig – dies ist aber ein übernommener Standard und kann übersetzbarer Texte, die in der Anwendung zum Einsatz kommen. Diese Da- nicht aus dem Dateinamen selbst abgeleitet werden. teien haben eine einfache interne Struktur, die eine Reihe von Name-Wert- i18n_en.properties Ein Ressourcenbündel mit englischem Text. Paaren enthält, die durch ein Gleichheitszeichen getrennt sind. Beispiel: i18n_en_GB.properties Ein Ressourcenbündel mit Text in britischem Englisch. appTitle=Suppliers And Products i18n_de.properties Ein Ressourcenbündel mit deutschem Text. Es ist wichtig zu verstehen, dass es innerhalb einer Datei .properties kein i18n_de_AT.properties Ein Ressourcenbündel mit Text in österreichischem Konzept für eine Objekthierarchie gibt. Die Struktur ist vollkommen flach. Deutsch.</p><p>In diesem Abschnitt betrachten wir die Dateispeicherorte, Dateinamenskon- Tabelle 5.1 Namenskonventionen für Ressourcenbündel ventionen und die Codepage für Ressourcenbündel. Danach setzen wir ein Ressourcenmodell in unserer Beispielanwendung ein. Bei der Ermittlung, welche Sprachressourcendatei geöffnet werden soll, wird vom Browser immer die spezifischste Datei zuerst angefordert. Wenn Ihr Browser auf das Gebietsschema UK eingestellt ist, wird i18_en_GB.properties 5.7.1 Dateispeicherort angefordert. Wird diese Datei nicht gefunden, wird vom Browser die nächs- Ressourcenbündel-Dateien werden normalerweise im Ordner i18n inner- te spezifischste Datei angefordert, die in diesem Fall i18n_en.properties wäre. halb der Verzeichnisstruktur der Anwendung abgelegt. Diese Dateien enden Wird diese Datei nicht gefunden, werden alle Gebietsschemawerte aus dem alle mit dem Suffix .properties, weshalb sie auch als »dot properties«-Dateien Dateinamen entfernt und einfach das Ressourcenbündel mit dem Text in der bezeichnet werden. Standardsprache i18n.properties angefordert. Dies ist als Fallback-Prozess zur Wenn wir unsere Beispielanwendung genau betrachten, erkennen wir, dass Ermittlung der Sprache bekannt. es einige Texte gibt, die nicht Teil der im JSON-Modell bereitgestellten Ge- schäftsdaten sind. Vielmehr gibt es Texte, die als Bezeichnungen oder Titel 5.7.3 Codepage dienen und übersetzt werden sollten, falls der Anwender die Anwendung in Es ist wichtig zu verstehen, dass in der Spezifikation für Ressourcenbündel- einer anderen Sprache ausführen möchte. Dateien festgelegt ist, dass alle Texte zur Codepage ISO-8859-1 (LATIN-1) ge- hören. Dies hat zwei wichtige Konsequenzen: 5.7.2 Dateinamenskonvention ̈ Bei der Verwendung der LATIN-1-Codepage wird davon ausgegangen, SAPUI5-Ressourcenbündel-Dateien folgen derselben Namenskonvention, dass der Text zu einer von links nach rechts verlaufenden Sprache gehört. die auch für Java-Ressourcenbündel verwendet werden. Es wird angenom- ̈ Texte, die zu Sprachen gehören, die den Einsatz einer anderen Codepage men, dass jede Datei, die mit .properties endet, einfache Name-Wert-Paare erfordern, z. B. fernöstliche Sprachen, müssen mit Unicode-Programmie-</p><p>210 211 4456.book Seite 212 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 213 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Ressourcenmodelle und Internationalisierung 5.7</p><p> rung statt mit dem nativen Skript der Sprache in die Ressourcenbündel- backToMaster=Back to Master List Datei eingegeben werden. masterViewTitle=Supplier Overview Wenn Sie z. B. hebräischen Text in eine Ressourcenbündel-Datei eingeben tableNoDataText=No data möchten, müssen Sie berücksichtigen, dass Hebräisch zum einen eine Nicht- masterTableTitle=Supplier tableIDColumnTitle=ID LATIN-1-Sprache und zum anderen eine von rechts nach links verlaufende tableNameColumnTitle=Name Sprache ist. Die hebräische Übersetzung für »Hello World« ist »Shalom Olam«. detailTitle=Supplier Detail ID=ID Um dieses Problem zu beheben, müssen Sie zuerst eine Ressourcenbündel- Listing 5.44 Standardmäßige .properties-Datei für die Beispielanwendung Datei mit dem Namen i18n_he.properties erstellen. Allerdings ist es nicht kor- rekt, das hebräische Skript direkt in diese Datei einzugeben. Wenngleich das Im nächsten Schritt müssen wir das Ressourcenmodell instanziieren. Dies er- hebräische Skript absolut korrekt ist, ist das folgende Beispiel inkorrekt: folgt in der Komponente, da dieses Modell über die Anwendung hinweg ver- helloWorld=! fügbar sein soll.</p><p>Stattdessen sollten Sie Folgendes eingeben: Es gibt zwei Bereiche im Component-Code, die wir ändern. Der erste Bereich ist Teil der Metadaten der Komponente, d. h. die Konfiguration. Definieren helloWorld=\u05E9\u05DC\u05D5\u05DD \u05E2\u05D5\u05DC\u05DD! Sie den Pfad zum Modell, wie in Listing 5.45 dargestellt. Zum einen wurden die hebräischen Zeichen in die hexadezimalen Unicode- metadata : { Werte umgewandelt, und zum anderen musste die Zeichenreihenfolge des "rootView": "sapui5.demo.mvcapp.view.App", hebräischen Satzes umgekehrt werden. Dies ist wichtig, da bei allen Texten "dependencies": { in einer .properties-Datei davon ausgegangen wird, dass sie im Links-nach- "minUI5Version": "1.28.0", rechts-Format festgelegt sind – selbst wenn der Text zu einer von rechts nach "libs": [ "sap.ui.core", "sap.m" ] }, links verlaufenden Sprache gehört! "config": { Im Browser wird die Reihenfolge der Zeichen in diesem String automatisch "i18nBundle": "sapui5.demo.mvcapp.i18n.i18n", umgekehrt, damit er korrekt gerendert wird. Weitere Informationen finden "serviceUrl": "webapp/service/data.json" }, Sie im Attribut dir="RTL" für UI-Controls. Listing 5.45 Auszug aus den Metadaten der Komponente</p><p>5.7.4 Verwenden eines Ressourcenmodells Der zweite Bereich ist die Methode init der Komponente. Greifen Sie hier Setzen wir nun unsere Beispielanwendung fort und ersetzen alle Texte, die auf den Konfigurationswert zu, instanziieren Sie das Ressourcenmodell über übersetzbar sein sollten, durch Werte aus einer .properties-Datei. den von Ihnen abgerufenen Pfad, und legen Sie es für die Komponente fest, die dieses wiederum an die untergeordneten Elemente (Views) propagiert Zuerst müssen Sie das Verzeichnis i18n innerhalb Ihres Anwendungsstamm- (siehe Listing 5.46). ordners erstellen. Danach müssen Sie die .properties-Datei innerhalb des i18n-Verzeichnisses erzeugen. Innerhalb dieses Verzeichnisses können .pro- init : function () { var mConfig = this.getMetadata().getConfig(); perties-Dateien für jede Sprache abgelegt werden, in die Ihre Anwendung // call the base component's init function übersetzbar sein soll. Eine typische .properties-Datei für unsere Anwendung UIComponent.prototype.init.apply(this, arguments); könnte wie in Listing 5.44 aussehen. // set the internationalization model notFoundTitle=Not Found this.setModel(new ResourceModel({ notFoundText=The resource was not found</p><p>212 213 4456.book Seite 214 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 215 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Ressourcenmodelle und Internationalisierung 5.7</p><p> bundleName : mConfig.i18nBundle backToMaster=Zurück zur Master-Liste }), "i18n"); }, masterViewTitle=Anbieter-Überblick Listing 5.46 init-Funktion in der Komponente tableNoDataText=Keine Daten masterTableTitle=Anbieter tableIDColumnTitle=ID Wir können nun die hartcodierten Strings in der Anwendung durch Werte tableNameColumnTitle=Name aus dem Modell ersetzen. Da es sich hier um ein benanntes Modell handelt, tablePriceColumnTitle=Preis können wir auf die Werte innerhalb der Bindungen mit einem Präfix wie z. B. i18n>detailTitle zugreifen (siehe Listing 5.47). detailTitle=Anbieter-Detail detailTableHeader=Anbieter-Produkte <mvc:View controllerName="sapui5.demo.mvcapp.controller.Detail" ID=ID xmlns:mvc="sap.ui.core.mvc" detailFilterLabel=Produkte Filtern xmlns:layout="sap.ui.layout" Listing 5.48 i18n.properties-Datei mit übersetzbaren Texten für die Anwendung xmlns="sap.m"> <Page id="page" navButtonPress="onNavPress" Sie können zwischen den verschiedenen Sprachen wechseln, indem Sie den showNavButton="true" Sprachparameter für Ihre Anwendung in der Adressleiste des Browsers wie title="{i18n>detailTitle}"> folgt festlegen: <content> <ObjectHeader http://yourpathtoyourapplication?sap-ui-language=fr id="objectHeader" title="{ Im Allgemeinen verwendet das Framework einen Sprachcode des Typs path: 'Name', string, um eine Sprache zu identifizieren. Hierzu gehören typischerweise formatter: '.formatter.formatUpperCase' Strings wie der BCP-47-Standard, de, en-US, zh-Hans-CN usw. Die Java-Ge- }" bietsschemasyntax und die SAP-eigenen Sprachcodes werden aber auch ak- number="{i18n>ID}: {ID}"> zeptiert. Weitere Informationen finden Sie im Entwicklerhandbuch. Listing 5.47 Auszug aus Detail-View mit Ressourcenmodell Die aktuelle Sprache wird aus verschiedenen Quellen ermittelt. In der folgen- Im Objekt-Header mit dem ID-Wert des Lieferanten sehen Sie, dass es auch den Liste finden Sie alle Quellen in umgekehrter Reihenfolge ihrer Priorität. möglich ist, Werte aus zwei verschiedenen Modellen, z. B. aus dem Ressour- Dies bedeutet, dass der letzte Eintrag in der Liste Vorrang vor den anderen cen- und dem Geschäftsdatenmodell, in einer Bindung zu kombinieren. hat: ̈ Sie sollten die Anwendung jetzt prüfen und die restlichen hartcodierten Hartcodierte SAPUI5-Standardgebietsschema 'en'. Strings ersetzen, damit die Anwendung vollständig übersetzbar wird. Auf ̈ Potenziell konfigurierte Browsersprache (window.navigator.browserLan- Wunsch können Sie danach eine weitere .properties-Datei zum Ordner i18n guage); für den Internet Explorer ist dies die Sprache des Betriebssystems. mit dem Suffix für die gewünschte Zielsprache hinzufügen und die Eigen- ̈ Potenziell konfigurierte Benutzersprache schaften aus Ihrer Quelldatei übersetzen. window.navigator.userLanguage; für den Internet Explorer ist dies die Region. Wenn Sie die Anwendungssprache im Browser ändern, können Sie sehen, Sprache in den Einstellungen wie bestimmte Strings durch die entsprechende Sprache ersetzt werden. Als ̈ Allgemeine Sprachinformationen vom Browser Beispiel haben wir eine zusätzliche deutsche .properties-Datei mit dem Na- window.navigator.language. men i18n_de.properties bereitgestellt (siehe Listing 5.48). ̈ Android: In der Zeichenfolge des Benutzeragenten enthaltene Sprache notFoundTitle=Nicht gefunden window.navigator.userAgent. notFoundText=Die Ressource wurde nicht gefunden</p><p>214 215 4456.book Seite 216 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 217 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings View-Modelle und das Gerätemodell 5.8</p><p>̈ Im Anwendungscode konfiguriertes Gebietsschema 5.8.1 Verwenden von View-Modellen jsdoc:symbols/sap.ui.core.Configuration. Mit einem View-Modell können Sie die Status der verschiedenen Elemente in ̈ Über die URL-Parameter konfiguriertes Gebietsschema. Ihrem View nachverfolgen. Damit können Sie eine Verbindung zwischen Werten, die durch die Anwendungslogik innerhalb des Controllers berech- Wenn Sie über die API auf die aktuelle Sprache zugreifen möchten, ist dies net werden, und den UI-Elementen herstellen, die z. B. aktiviert/deaktiviert, über die entsprechende Methode im Konfigurationsobjekt möglich: ein-/ausgeblendet oder aktiv/inaktiv sein müssen. var sCurrentLocale = sap.ui.getCore().getConfiguration().getLanguage(); Immer wenn Sie einen Wert aus Ihrem Geschäftsdatenmodell nicht über die typischen Bindungsmethoden an den View übergeben können, sondern die Wenn Sie direkt aus dem Code auf einen Wert im Ressourcenmodell zugrei- Werte auf Basis verschiedener Bedingungen berechnen müssen, sollten Sie fen müssen, z. B. wenn Sie einen Wert innerhalb einer Formatierung ver- ein View-Modell verwenden. So können Sie die Controller-Logik und die wenden müssen, können Sie als Modul jQuery.sap.resources nutzen. Die- Deklaration des Views voneinander trennen, da somit verhindert wird, dass ses Modul enthält eine API, mit der Sie abhängig von der URL und dem der Controller etwas über die bestimmten Controls innerhalb der Views und Gebietsschema, das Sie an das Modul übergeben, ein Ressourcenbündel ab- deren jeweiligen Status erfahren muss. rufen können. Wir möchten dies anhand eines Beispiels verdeutlichen. Wir implementie- Sie müssen hier allerdings sicherstellen, dass das Modul tatsächlich vorhan- ren eine Funktion, mit der wir die Lieferanten innerhalb der Anwendung den und in Ihrer Anwendung geladen ist. Hierzu können Sie das Modul ex- durchblättern können. Wenn ein Anwender den Detail-View für einen Liefe- plizit wie folgt anfordern: ranten öffnet, wird ihm rechts oben im View ein Button zum Vor- und/oder jQuery.sap.require("<a href="/tags/JQuery/" rel="tag">jquery</a>.sap.resources"); Zurückblättern angezeigt. Wenn er auf eine dieser Buttons klickt, wird ein Routingereignis ausgelöst, und der Anwender gelangt zum nächsten bzw. Anschließend können Sie mit dem Modul das gewünschte Ressourcenbündel vorherigen Lieferanten. abrufen:</p><p> var oBundle = jQuery.sap.resources({url : sUrl, locale: sLocale}); Der Detail-View in der Anwendung sieht nun wie in Listing 5.49 aus.</p><p>Weitere Informationen erhalten Sie im SAPUI5-Demokit auf der Registerkar- <mvc:View controllerName="sapui5.demo.mvcapp.controller.Detail" xmlns:mvc="sap.ui.core.mvc" te API Reference unter jQuery.sap.resources. Nachdem Sie das Ressour- xmlns:layout="sap.ui.layout" cenbündel in Ihre Anwendung geladen haben, können Sie die Methode get- xmlns="sap.m"> Text auf die Gruppe anwenden, um über den Schlüssel auf bestimmten Text <Page id="page" zuzugreifen: navButtonPress="onNavPress" showNavButton="true" var sText = oBundle.getText(sKey); title="{i18n>detailTitle}"> <subHeader> <Toolbar> 5.8 View-Modelle und das Gerätemodell <ToolbarSpacer/> <Button icon="sap-icon://slim-arrow-up" press="onPageUp" /> <Button icon="sap-icon://slim-arrow-down" press= Die letzten beiden in diesem Kapitel besprochenen Modelle sind eigentlich "onPageDown" /> keine unterschiedlichen Modelltypen, sondern es kann sich dabei um belie- </Toolbar> bige Modelle handeln. Allerdings verwenden wir wieder JSON-Modelle in </subHeader> der Beispielanwendung. <content> [...] Listing 5.49 Geänderte Kopfzeile im Detail-View </p><p>216 217 4456.book Seite 218 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 219 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings View-Modelle und das Gerätemodell 5.8</p><p>Wir verwenden hierzu spezielle Symbole für die beiden Buttons, die zum deshalb eine weitere Eigenschaft zu jedem der beiden Buttons, und zwar die Blättern entwickelt wurden. (Mit ToolbarSpacer wird sichergestellt, dass die Eigenschaft enabled hinzu, und binden wir diese an das View-Modell (siehe Buttons rechtsbündig sind.) Die Herausforderung ist es jetzt, diese Buttons Listing 5.51). abhängig davon zu aktivieren bzw. zu deaktivieren, ob es einen nächsten <Toolbar> bzw. vorherigen Lieferanten überhaupt gibt. Wird der erste Lieferant in der <ToolbarSpacer/> Liste angezeigt, ergibt es keinen Sinn, einen aktiven Back-Button bereitzu- <Button icon="sap-icon://slim-arrow-up" press= stellen. "onPageUp" enabled="{viewModel>/buttonPrev}" /> <Button icon="sap-icon://slim-arrow-down" press= Wir könnten fortfahren und die Methoden verwenden, mit denen wir zuvor "onPageDown" enabled="{viewModel>/buttonNext}" /> Informationen über die Position des Lieferanten in der Liste abgerufen ha- </Toolbar> ben. Um jedoch die Buttons aus dem Controller dynamisch zu aktivieren und Listing 5.51 Binden an das View-Modell zu deaktivieren, müssten wir den Code in den Controller schreiben, der den Status des Buttons aktualisiert, wenn der Bindungskontext im View auf Wenn Sie die Seite neu laden, sehen Sie, dass nun beide Buttons deaktiviert einen anderen Lieferanten wechselt. Zudem müsste dem Controller genau sind. Egal welchen Lieferanten Sie jetzt auswählen, Sie können keinen ankli- bekannt sein, welche Buttons im View sind, indem auf diese z. B. über ihre cken (siehe Abbildung 5.12). IDs zugegriffen wird. Um dies zu entkoppeln und so den Code möglichst wiederverwendbar und verwaltbar zu gestalten, sollte die Controller-Logik unabhängig von den im View sichtbaren Buttons sein.</p><p>Glücklicherweise gibt es eine einfache Lösung für dieses Dilemma: Erstellen Sie ein weiteres Modell im Ereignis onInit des Detail-Views. Dieses Modell ist ein normales JSON-Modell, das wir als benanntes Modell im View festle- gen. Es enthält nur wenige Daten (in diesem Fall sind nur zwei Werte erfor- derlich), weshalb wir die Werte des Modells direkt dort bestimmen können, wo das Modell instanziiert ist. Abbildung 5.12 Lieferantendetails mit Objekt-Header Der Handler onInit im Detail-View sieht nun wie in Listing 5.50 aus.</p><p> onInit : function () { Es fehlt noch die Logik, mit der das View-Modell aktualisiert wird, wenn das this.getRouter().getRoute("detail").attachPatternMatched(this._ Element bindingContext für den View und die Funktionalität für die Naviga- onObjectMatched, this); tion geändert wird. var oModel = new sap.ui.model.json.JSONModel({ buttonPrev: false, Wir müssen diese Logik so implementieren, dass sie ausgelöst wird, wenn buttonNext: false die Funktion bindElement im View aufgerufen wird, was in der Methode }); onObjectMatched this.getView().setModel(oModel, "viewModel"); des Detail-Views geschieht. }, Um einen klaren Code zu erhalten, schreiben wir unsere eigene Funktion, [...] mit der wir den korrekten Zustand ermitteln können. Diese Funktion kön- Listing 5.50 Instanziieren eines View-Modells nen wir dann aus der Methode onObjectMatched aufrufen.</p><p>Die beiden Eigenschaften enthalten nun boolesche Werte, die wir auch zum Die neue Funktion muss die aktuelle Position eines Lieferanten im Modell Binden der aktivierten Eigenschaften aus den Buttons verwenden. Hierzu abrufen und anhand dieser Informationen den Status, in dem sich die But- verwenden wir die normale Property-Binding-Syntax im View. Fügen wir tons befinden sollten, berechnen. Außerdem speichern wir die Informatio-</p><p>218 219 4456.book Seite 220 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 221 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings View-Modelle und das Gerätemodell 5.8</p><p> nen über die Position im View-Modell, da diese im Navigations-Event-Hand- * ler wiederverwendet werden. * @function * @param {sap.ui.base.Event} oEvent pattern match event in Wir können die Informationen abrufen und das View-Modell aktualisieren, * route 'object' indem wir die Codezeilen aus Listing 5.52 zum Detail-Controller hinzufügen. * @private */ /** _onObjectMatched : function (oEvent) { * Updates the view model according to whether there are previous this.sObjectID = oEvent.getParameter("arguments").ID; * and/or next suppliers. this.sObjectPath = "/Suppliers/" + this.sObjectID; * this._bindView(); * @function this._updateViewModel(); * @param {string} sObjectID path to the current supplier object }, * @private [...] */ Listing 5.53 Aktualisieren des gebundenen Lieferanten und des View-Modells aus der _updateViewModel : function() { Funktion _onObjectMatched //find out if there is a next object in the line: var oModel = this.getView().getModel(); var oViewModel = this.getView().getModel("viewModel"); Beachten Sie, wie wir gleichzeitig die Dokumentation für diese Methode var nextObjectId = parseInt(this.sObjectID) + 1; aktualisiert haben. Wenn Sie nun die Seite neu laden, wird der korrekte But- var prevObjectId = parseInt(this.sObjectID) - 1; ton-Status abhängig davon gepflegt, ob wir uns beim ersten oder letzten Lie- // check if there is a next object by adding +1 to the feranten befinden. Allerdings können wir mit diesen Buttons immer noch // supplier ID we assume we get a field we can safely nicht navigieren, da die entsprechenden Event-Handler für die press-Ereig- // order from the server var bNext = !!oModel.getProperty("/Suppliers/" + nextObjectId); nisse noch fehlen. var bPrev = !!oModel.getProperty("/Suppliers/" + prevObjectId); Wir fügen die Methode onPagingButtonPress sowohl zum XML-View als oViewModel.setProperty("/buttonNext", bNext); Event-Handler für die Buttons als auch zum Controller hinzu, in dem die ei- oViewModel.setProperty("/buttonPrev", bPrev); } gentliche Navigation implementiert wird. Da wir innerhalb der Anwendung Listing 5.52 Binden des Views an den richtigen Kontext und Berechnen der ein entsprechendes Routing verwenden, können wir jetzt einfach dieses Button-Aktivierung Routing durch Aufruf der entsprechenden Funktion navTo mit den Informa- tionen über den nächsten bzw. vorherigen Lieferanten nutzen. Hier versuchen wir, die nächsten und die vorherigen Lieferanten abzurufen, Wie bereits erwähnt, gehen wir in unserem Szenario davon aus, dass wir den indem wir 1 zur aktuellen ID addieren bzw. diesen Wert davon subtrahie- Index des Lieferanten um 1 erhöhen bzw. um 1 verringern können, um den ren. Hierbei gehen wir davon aus, dass das ID-Feld ein Feld ist, mit dem wir nächsten bzw. vorherigen Lieferanten zu erhalten. Daher müssen wir nur die die Reihenfolge sicher bestimmen können (was in den meisten Fällen nicht beiden Funktionen in Listing 5.54 schreiben. funktionieren würde). Normalerweise sollte der Service dazu in der Lage sein, Informationen über das nächste bzw. vorherige Objekt einer Samm- onPageUp : function(oEvent) { lung bereitstellen zu können. var sID = oEvent.getSource().getBindingContext().getPath(); sID = parseInt(sID.substr(sID.lastIndexOf("/")+1)); Als Nächstes müssen wir die Codezeile hinzufügen, mit der diese Funktion sID = sID-1; ausgelöst wird (siehe Listing 5.53). this.getRouter().navTo("detail", {ID: sID}); }, [...] /** onPageDown : function(oEvent) { * Binds the view to the object path and maintains the paging var sID = oEvent.getSource().getBindingContext().getPath(); * button state. sID = parseInt(sID.substr(sID.lastIndexOf("/")+1));</p><p>220 221 4456.book Seite 222 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 223 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings View-Modelle und das Gerätemodell 5.8</p><p> sID += 1; return { this.getRouter().navTo("detail", {ID: sID}); createDeviceModel: function () { }, var oModel = new JSONModel(Device); Listing 5.54 Navigationsfunktionen zum Blättern durch die Lieferanten über oModel.setDefaultBindingMode("OneWay"); die Pfeil-Buttons return oModel; } }; Wir verwenden den Pfad aus dem Ereignisobjekt, das an den Event-Handler }); übergeben wurde, und extrahieren die aktuelle Lieferantennummer aus die- Listing 5.55 Implementieren eines Gerätemodells für die Anwendung sem Pfad. Wir wandeln diese in eine ganze Zahl um, da das Hinzufügen von +1 eine Zeichenfolgenverkettung auslösen würde. Dann subtrahieren wir Die in den Aufruf sap.ui.define übergebenen Parameter sind zwei Klassen, entweder 1, wenn ein Anwender auf den Pfeil nach oben klickt, oder addie- die wir innerhalb dieses Modells benötigen, um alle Informationen über den ren 1, wenn der Anwender nach unten navigiert. Wir übergeben das Ergeb- aktuellen Client aus der API sap.ui.Device zu erhalten und diese innerhalb nis als Parameter ID an die Funktion navTo, damit die Navigation zum nächs- eines JSON-Modells zu speichern. ten oder vorherigen Lieferanten ausgelöst wird und diese entsprechend angezeigt werden. Wenn dieses Modell aufgerufen wird, wird eine neue Funktion createDe- viceModel zurückgegeben. Innerhalb dieser Funktion erstellen wir ein neues JSON-Modell aus den Daten, die wir aus der Geräte-API abgerufen haben. 5.8.2 Verwenden des Gerätemodells Da dieses Modell Informationen in Schlüssel-Wert-Paaren bereitstellt, kön- Das Gerätemodell ist ein normales JSON-Modell, das wir separat behandeln, nen wir das Objekt an den JSON-Modell-Konstruktor übergeben. da es eine besondere Bedeutung innerhalb der Anwendung hat. Dieses Mo- Anschließend setzen wir bindingMode auf OneWay, da es nicht sinnvoll ist, die dell wird jedoch nicht für einen bestimmten View implementiert, sondern Werte innerhalb des Modells aus dem Anwendungscode zu manipulieren. ganz allgemein in der Anwendung eingesetzt. Damit werden die Control- Schließlich geben wir das neu erstellte Modell zurück. Wenn wir nun zur Eigenschaften nachverfolgt, die abhängig davon angepasst werden müssen, Anwendungskomponente zurückgehen, müssen wir das neue Modell nur in ob die Anwendung auf einem Desktop-PC oder einem Mobilgerät (Touch- die Komponente einfügen. screen) angezeigt wird. Wir müssen die entsprechende Ressource zum Abschnitt define der Kompo- Dies ist insbesondere für einige Eigenschaften sinnvoll, die sich auf das Aus- nente hinzufügen (siehe Listing 5.56). sehen auswirken, z. B. die aktiven Zustände eines Controls, auf das Sie ge- tippt oder geklickt haben. Da dieses Modell in mehr als einem View verwen- sap.ui.define([ det werden kann, implementieren wir dieses separat und instanziieren es "sap/ui/core/UIComponent", innerhalb der Komponente. "sap/ui/model/resource/ResourceModel", "sap/ui/model/json/JSONModel", Die Implementierung für das Modell selbst erfolgt in einer separaten Datei, "sap/ui/Device" die wir im vorhandenen Verzeichnis model der Anwendung ablegen und mo- ], function (UIComponent, ResourceModel, JSONModel, Device) { "use strict"; dels.js nennen. Listing 5.56 Hinzufügen von Ressourcen für das Gerätemodell Der Code für dieses Modell ist in Listing 5.55 dargestellt.</p><p> sap.ui.define([ Innerhalb der Funktion init der Komponente fügen Sie den Code für die zu- "sap/ui/model/json/JSONModel", sätzliche Modellinstanziierung, wie in Listing 5.57 dargestellt, ein. "sap/ui/Device" init : function () { ], function (JSONModel, Device) { var mConfig = this.getMetadata().getConfig(); "use strict";</p><p>222 223 4456.book Seite 224 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 225 Mittwoch, 9. November 2016 10:03 10</p><p>5 Modelle und Bindings Fazit 5.9</p><p>// call the base component's init function Wir können diese aber wieder aktivieren, indem wir in Google Chrome in UIComponent.prototype.init.apply(this, arguments); den Emulationsmodus wechseln. So können wir ermitteln, wie die Anwen- dung auf einem Smartphone aussieht. // set the internationalization model this.setModel(new ResourceModel({ bundleName : mConfig.i18nBundle }), "i18n"); 5.9 Fazit</p><p>// create the device model here In diesem Kapitel haben Sie die clientseitigen Modelle und deren Einsatz in var oModel = new JSONModel(Device); SAPUI5 kennengelernt. Sie haben erfahren, wie Modelle instanziiert wer- oModel.setDefaultBindingMode("OneWay"); this.setModel(oModel, "Device"); den, und Sie haben die typischen Data-Binding-Methoden in der Beispiel- anwendung verwendet. // create the views based on the url/hash this.getRouter().initialize(); Mit diesem Wissen haben wir die Anwendung soweit erweitert, dass die }, gängigsten Funktionen in den Anwendungen der Enterprise-Klasse ange- Listing 5.57 In der Funktion init instanziiertes Gerätemodell sprochen wurden. Wir haben die Anwendung mithilfe eines Ressourcenmo- dells multilingual gestaltet und eine plattformübergreifende Kompatibilität Nun können wir über unsere Views auf das Gerätemodell zugreifen. Mithilfe erzielt, indem wir ein Gerätemodell für jene Funktionen umgesetzt haben, der Informationen darüber, welches Gerät auf die Anwendung zugreift, kön- die auf Desktop-PCs und typischen Mobilgeräten unterschiedlich gehand- nen wir bestimmen, ob wir Controls anzeigen oder ausblenden, deren Ver- habt werden müssen. halten ändern oder Informationen in einem anderen Control anzeigen möch- In Kapitel 6, »CRUD-Operationen«, fahren wir mit der Erweiterung der An- ten. Wir könnten z. B. die Blätter-Buttons anzeigen lassen, die wir nur für wendung fort, indem wir Mittel zur Manipulation der Daten in einem Mo- Smartphone-Bildschirme für die Lieferanten erstellt haben. dell aus der Anwendung heraus hinzufügen. Dieses Mal verwenden wir aber In diesem Fall mussten wir nur die Zeilen im Detail-View ändern, die die einen echten Service anstelle von lokalen Beispieldaten. entsprechenden Text-Controls, wie in Listing 5.58 dargestellt, instanziieren.</p><p><Toolbar> <ToolbarSpacer/> <Button icon="sap-icon://slim-arrow-up" press="onPageUp" enabled="{viewModel>/buttonPrev}" visible="{device>/system/phone}" /> <Button icon="sap-icon://slim-arrow-down" press="onPageDown" enabled="{viewModel>/buttonNext}" visible="{device>/system/phone}"/> </Toolbar> Listing 5.58 Verwenden von Eigenschaften aus dem Gerätemodell für Bindungen</p><p>Die Anwendung sieht nun im Desktop-Modus ein wenig anders aus, bei dem die Pfeil-Buttons nicht mehr im Detail-View angezeigt werden.</p><p>224 225 4456.book Seite 15 Mittwoch, 9. November 2016 10:03 10</p><p>Einleitung2 </p><p>SAPUI5 ist das neue Toolkit von SAP zur Programmierung von Benutzer- oberflächen als wichtiger Bestandteil in der aktuellen Technologiestrategie von SAP. Insbesondere handelt es sich dabei um die Technologie, die zur Entwicklung von SAP-Fiori-Anwendungen genutzt wird, die den neuen Stan- dard für das moderne Aussehen von SAP-Anwendungen verkörpern.</p><p>Mit SAPUI5 erstellte Anwendungen sind mit verschiedensten Browsern und Geräten einsetzbar und bieten eine integrierte Erweiterbarkeit, funktionsrei- che UI-Controls für komplexe Muster und Layouts, die Übersetzung in meh- rere Sprachen und Barrierefreiheitsfunktionen. Die Steuerung all dieser Funktionen kann wegen ihrer Komplexität einschüchternd wirken. Und ge- nau hier kommt dieses Buch ins Spiel! Mit diesem umfassenden Handbuch können Sie Ihre Codefähigkeiten verfeinern und die SAPUI5-Sprache sicher erlernen. Egal ob Sie mit den Grundbausteinen beginnen oder erweiterte Funktionen in Ihrem Code umsetzen möchten – dieses Buch begleitet Sie auf Ihrer gesamten SAPUI5-Reise.</p><p>An wen richtet sich das Buch?</p><p>Dieses Buch wurde für alle Entwickler konzipiert und geschrieben, die be- reits über grundlegende Kenntnisse in der Webentwicklung und in Java- Script verfügen und ihr Wissen über den Aufbau von Anwendungen mit SAPUI5 vertiefen möchten. Entwickler mit einem anderen Hintergrund soll- ten sich von dieser Aussage aber nicht abschrecken lassen! Wenn Sie mit die- sem Buch arbeiten, empfehlen wir Ihnen, dass Sie entweder parallel ein gutes JavaScript-Buch verwenden oder vor der Buchlektüre eine der zahlrei- chen Onlinequellen zu den JavaScript-Grundlagen zurate ziehen. Für alle ABAP-Entwickler nochmals der Hinweis: Denken Sie daran, dass in Java- Script die Groß-/Kleinschreibung berücksichtigt wird.</p><p>Ziel dieses Buches</p><p>Ziel dieses Buches ist es, Ihnen das nötige Wissen zu vermitteln, um voll ein- satzfähige SAPUI5-Anwendungen entwickeln zu können. Am Ende der Lek- türe sollten Sie umfassende Kenntnisse über die hierzu notwendigen Kon-</p><p>15 4456.book Seite 16 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 17 Mittwoch, 9. November 2016 10:03 10</p><p>Einleitung Wie das Buch zu lesen ist</p><p> zepte sowie ein praktisches Verständnis dafür entwickelt haben, wie diese nen. Hierzu gehören Property, Element, Aggregation und Expression Konzepte beim Aufbau echter Anwendungen angewendet werden. Binding. ̈ In Kapitel 6, »CRUD-Operationen«, beginnen wir, unsere Anwendungen mit der »echten Welt«, d. h. mit echten Services zu verknüpfen. Außerdem Wie das Buch zu lesen ist erfahren Sie, wie typische Anfragen an das Backend erstellt werden. Da- rüber hinaus erläutern wir wichtige Funktionen wie das Filtern, Sortieren, Das Buch und die einzelnen Kapitel bauen aufeinander auf. Zu Beginn wer- Gruppieren und Erweitern. den die Grundlagen für den Aufbau von SAPUI5-Anwendungen erläutert, ̈ In Kapitel 7, »Einsatz von OData«, stellen wir eines der wichtigsten REST- und im weiteren Buchverlauf werden nach und nach komplexere Konzepte basierten Protokolle vor: OData. Wir zeigen Ihnen, wie Sie eine Anwen- vorgestellt. dung mit einem OData-Modell verknüpfen können, und gehen auf die Teil I, »Einführung«, bietet eine Einführung in SAPUI5 und dessen Architek- weiteren Funktionen von OData ein. tur. Teil I enthält die folgenden Kapitel: ̈ In Kapitel 8, »Anwendungsmuster und -beispiele«, erkunden wir die am ̈ In Kapitel 1, »SAPUI5 auf einen Blick«, geben wir eine Einführung in häufigsten verwendeten Anwendungsmuster in SAPUI5. Wir betrachten SAPUI5 im Allgemeinen. Hierzu gehören Informationen über die Ge- auch die Bereitstellung unserer Anwendungen im Portal SAP Fiori Launch- schichte des Produkts, seine Entwicklung, Funktionen, Anwendungsfälle, pad, das für SAP-Fiori- und SAPUI5-Anwendungen verwendet wird. Konkurrenzprodukte und die Open-Source-Variante OpenUI5. ̈ In Kapitel 9, »Weiterführende Konzepte«, zeigen wir Ihnen, wie Sie Ihre ̈ In Kapitel 2, »Architektur«, gehen wir näher auf die Architektur von Anwendungen noch weiter verbessern können! Sie erfahren, wie Sie ODa- SAPUI5 sowie auf die Bibliotheken, Elemente und die Strukturhierarchie ta-Annotations zur Anreicherung der intelligenten Controls einsetzen oder ein. die SAPUI5-Funktionalität durch das Schreiben von eigenen Controls er- weitern können. In Teil II, »SAPUI5 in Aktion – Entwicklung von Anwendungen«, widmen wir uns den einzelnen Schritten für den Aufbau von Anwendungen unter Teil III, »Der letzte Schliff«, gibt unserer Anwendungsentwicklung den letz- der Verwendung von SAPUI5 – von »Hello, World« bis hin zu erweiterten ten Schliff. Hier erhalten Sie Informationen dazu, wie Sie SAPUI5-Anwen- Konzepten wie dem Schreiben von eigenen Controls. Teil II beinhaltet die dungen definieren, debuggen und bereitstellen können. Teil III beschäftig folgenden Kapitel: sich mit den folgenden Kapiteln:</p><p>̈ Kapitel 3, »Hello, SAPUI5 World«, startet mit einem einfachen »Hello, ̈ In Kapitel 10, »Enterprisetaugliche Anwendungen erzeugen«, stellen wir World«-Anwendungsbeispiel. Hier werden Sie durch die ersten und wich- Ihnen alle wichtigen Enterprise-Funktionen vor, die Sie zur Erweiterung tigsten Schritte bei der Entwicklung von Anwendungen mit SAPUI5 ge- Ihrer Anwendungen einsetzen können. Hierzu gehören der Einsatz von führt. In diesem Kapitel betrachten wir die Struktur einer einseitigen An- Unternehmensprofilen sowie die Implementierung von Sicherheitsmaß- wendung sowie die wichtigsten Bausteine von SAPUI5: die Controls, nahmen und Leistungsoptimierungen. Außerdem erhalten Sie Richtlinien, deren Funktionalität und deren API. damit Sie Ihre Anwendungen Menschen mit Behinderungen zugänglich ̈ Kapitel 4, »Aufbau von MVC-Anwendungen«, baut auf den in Kapitel 3 machen können. vorgestellten Konzepten auf und geht näher auf Anwendungsmodelle, ̈ In Kapitel 11, »Debuggen und Testen von Code«, werden die Schritte er- Views und Controller ein. läutert, mit denen Sie die Einsatzbereitschaft Ihrer Anwendungen sicher- ̈ In Kapitel 5, »Modelle und Bindings«, erläutern wir die allgemeine Nut- stellen können. Hierzu gehört das manuelle Debuggen und das Schreiben zung und die Modelltypen in SAPUI5. Wir erörtern auch die unterschied- automatischer Tests, die Stabilität und fehlerfreien Anwendungscode ge- lichen Arten des Data Bindings, die in SAPUI5 implementiert werden kön- währleisten.</p><p>16 17 4456.book Seite 18 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 19 Mittwoch, 9. November 2016 10:03 10</p><p>Einleitung Danksagung</p><p>̈ In Kapitel 12, »Was Sie nicht tun sollten«, zeigen wir Ihnen, wie Sie Ihre Danksagung Anwendungen ordentlich durcheinanderbringen können. In diesem Kapi- tel finden Sie die »Worst Practices« und Möglichkeiten, wie Sie Ihre An- Unser besonderer Dank geht an unsere Kollegen des zentralen SAPUI5- wendungen ruinieren können. Teams in Walldorf und in Sofia, die fortlaufend an der Verbesserung dieses Frameworks arbeiten. Ohne deren Beiträge wäre dieses Buch nicht möglich Das Buch schließt mit einigen hilfreichen Anhängen zur Abrundung des gewesen. SAPUI5-Themas ab: Wir danken Chris Whealy für seine Hilfe und Unterstützung – beim Schrei- ̈ In Anhang A, »IDE-Einrichtung«, erhalten Sie die grundlegenden Konfi- ben von Büchern im Allgemeinen und für sein Lektorat und sein nützliches gurationsrichtlinien für den Einsatz gängiger IDEs innerhalb von SAP ein- Feedback! schließlich der SAP Web IDE und WebStorm. Auch die Autoren möchten ihre persönlichen Danksagungen aussprechen: ̈ In Anhang B, »Zugriff auf das Backend«, geben wir Ihnen Tipps und Tricks für den Zugriff auf das Backend, einschließlich des Zugriffs auf die SAP Danke an meinen Partner, meine Familie und meine Freunde, die viel Ge- HANA Cloud Platform (SAP HCP) und Sicherheits-Plug-ins für Google duld mit mir hatten und sich nicht beschwert haben, als ich zum 100. Mal Chrome. eine Einladung mit den Worten »Ich muss noch Kapitel XY abschließen.« aus- ̈ In Anhang C, »Deployment von Anwendungen«, erläutern wir die Schrit- geschlagen habe. te für die Bereitstellung Ihrer Anwendungen in unterschiedlichen Plattfor- – Christiane Goebels men wie z. B. der SAP HCP, der SAP Web IDE und dem ABAP-Server. ̈ In Anhang D, »Cheat Sheets«, erhalten Sie Kurzanleitungen für wichtige Codekonzepte, z. B. zum Starten einer Anwendung, zum Durchführen von Ich möchte meinen Freunden, Kollegen und meiner Familie danken, die Data Bindings usw. mich auf dieser Reise und beim Schreiben dieses Buches motiviert und ermu- ̈ In Anhang E, »Weitere Ressourcen«, finden Sie eine umfangreiche Liste tigt haben. Ein großes Dankeschön geht an meine großartigen Mitautoren mit Ressourcen zum Weiterlernen. Diese reichen von Links zu openSAP- Christiane und Thilo. Es war mir eine Freude, mit Euch zusammenzuarbei- Kursen und Dokumentationen bis hin zu Webseiten und GitHub-Reposi- ten! Ein weiteres großes Dankeschön geht an meinen Vorgesetzten Christian torys. Paulus, der dieses Buchprojekt von Anfang an unterstützt hat und viel Ver- ständnis hatte, wenn ich kurzfristig Urlaub nehmen musste, wenn ein weite- Begleitmedien rer Abgabetermin anstand.</p><p>Im gesamten Buch verwenden wir Beispiele, Schritt-für-Schritt-Anleitungen und Ein besonderer Dank geht an unsere Lektorin Sarah Frazier, die großartige Beispielcode, um die relevanten Konzepte praktisch darzustellen. Den Beispiel- Arbeit geleistet hat und deren ermutigenden Worte mir beim Abschluss die- code und andere zusätzliche Inhalte zu diesem Buch finden Sie auf der Webseite ses Projekts geholfen haben. des Buches unter https://www.sap-press.de/4303/. – Denise Nepraunig Wir hoffen, dass Sie beim Lesen und Umsetzen dieses Buches so viel Spaß haben, wie wir es beim Schreiben hatten. Lassen Sie uns anfangen! Ich möchte all den großartigen Menschen danken, die SAPUI5 entwickeln, unterstützen, nutzen und fördern. Insbesondere danke ich den internen SAPUI5-Entwicklungsteams und den Kollegen, die es nie leid waren, all mei-</p><p>18 19 4456.book Seite 20 Mittwoch, 9. November 2016 10:03 10</p><p>Einleitung</p><p> ne Fragen in den letzten Jahren und insbesondere bei der Entstehung dieses Buches zu beantworten.</p><p>Außerdem möchte ich den Mitarbeitern von OpenUI5 danken, die wichtige Teile von SAPUI5 als Open Source freigegeben haben. Ihr seid großartig!</p><p>Persönlich möchte ich Sonia dafür danken, dass sie stolz auf mich ist; Mattis danke ich, dass es ihn gibt; Denise und Christiane danke ich, dass ich bei die- sem Buch Mitautor sein durfte!</p><p>– Thilo Seidel</p><p>20 4456.book Seite 5 Mittwoch, 9. November 2016 10:03 10</p><p>Auf einen Blick</p><p>TEIL I Einführung 1 SAPUI5 auf einen Blick ...... 23 2 Architektur ...... 43</p><p>TEIL II SAPUI5 in Aktion – Entwicklung von Anwendungen 3 Hello, SAPUI5 World ...... 61 4 Aufbau von MVC-Anwendungen ...... 91 5 Modelle und Bindings ...... 161 6 CRUD-Operationen ...... 227 7 Einsatz von OData ...... 277 8 Anwendungsmuster und -beispiele ...... 361 9 Weiterführende Konzepte ...... 425</p><p>TEIL III Der letzte Schliff 10 Enterprisetaugliche Anwendungen erzeugen ...... 477 11 Debuggen und Testen von Code ...... 519 12 Was Sie nicht tun sollten ...... 577 4456.book Seite 7 Mittwoch, 9. November 2016 10:03 10</p><p>Inhalt</p><p>Einleitung ...... 15</p><p>TEIL I Einführung</p><p>1 SAPUI5 auf einen Blick ...... 23</p><p>1.1 Was ist SAPUI5, und wo ist es erhältlich? ...... 23 1.2 Entstehung und Entwicklung ...... 24 1.3 Funktionen ...... 25 1.3.1 SAPUI5-Demokit ...... 26 1.3.2 Model View Controller in SAPUI5 ...... 29 1.3.3 Browserübergreifende Kompatibilität ...... 29 1.3.4 Themes ...... 32 1.3.5 Lokalisierung ...... 33 1.3.6 Barrierefreiheit ...... 33 1.3.7 Open Source in SAPUI5 ...... 34 1.4 Anwendungsfälle ...... 35 1.5 Produktvergleich ...... 38 1.6 SAPUI5 und OpenUI5 ...... 39 1.7 Fazit ...... 40</p><p>2 Architektur ...... 43</p><p>2.1 Die Bibliotheken ...... 43 2.2 MVC-Überblick ...... 46 2.2.1 MVC-Interaktion ...... 47 2.2.2 Instanziierung des Views und Controller- Lebenszyklus ...... 48 2.3 Architektur einer typischen SAPUI5-Anwendung ...... 49 2.4 Klassenhierarchien ...... 52 2.4.1 Vererbung für Controls ...... 53 2.4.2 Vererbung für Modelle ...... 55 2.5 Fazit ...... 58</p><p>7 4456.book Seite 8 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 9 Mittwoch, 9. November 2016 10:03 10</p><p>Inhalt Inhalt</p><p>TEIL II SAPUI5 in Aktion – Entwicklung von Anwendungen 4.5 Komponenten ...... 135 4.5.1 Erstellen der Component-Datei ...... 135 3 Hello, SAPUI5 World ...... 61 4.5.2 Hinzufügen einer Shell zur Component-Datei ...... 139 3.1 Richtlinien für die Programmierung ...... 61 4.5.3 Optimieren des Aussehens einer Tabelle ...... 141 3.1.1 Globale Variablen ...... 62 4.5.4 Component Metadata ...... 143 3.1.2 Private Objektmitglieder ...... 63 4.5.5 Speichern der hartcodierten Modelldaten in 3.1.3 Codeformatierung ...... 64 einer separaten Datei data.json ...... 143 3.1.4 Namenskonventionen für Variablen ...... 65 4.6 Routing ...... 146 3.2 Einrichtung ...... 66 4.6.1 Konfiguration des Routings ...... 147 3.2.1 Einrichten Ihrer HTML-Startseite ...... 66 4.6.2 Initialisierung des Routers ...... 150 3.2.2 Bootstrapping in SAPUI5 ...... 67 4.6.3 Anpassen des Anwendungs-Views ...... 150 3.3 Hinzufügen eines einfachen Controls ...... 69 4.6.4 Verwenden des Routings innerhalb des 3.4 Definieren eines Event-Handlers ...... 71 Master-Controllers ...... 151 3.4.1 Einfacher Event-Handler ...... 71 4.6.5 Verwenden des Routings innerhalb des 3.4.2 Verwenden von Ereignisinformationen innerhalb Detail-Controllers ...... 153 eines Event-Handlers ...... 74 4.7 Anwendungsdeskriptor ...... 155 3.5 Komplexe Controls ...... 76 4.8 Fazit ...... 160 3.5.1 Aggregationen ...... 76 3.5.2 Assoziationen ...... 78 5 Modelle und Bindings ...... 161 3.6 API der Controls ...... 81 5.1 Verwenden von Modellen – ein JSON-Beispiel ...... 162 3.7 Layouts ...... 82 5.1.1 Instanziierung und Laden der Daten ...... 162 3.8 Fazit ...... 88 5.1.2 Zugriff auf Modellwerte ...... 165 5.2 Property Binding ...... 170 4 Aufbau von MVC-Anwendungen ...... 91 5.2.1 Methoden zum Binden der Eigenschaft 4.1 Modelle, Views und Controller ...... 91 eines Controls ...... 171 4.2 Struktur ...... 93 5.2.2 Verwenden von Datentypen ...... 175 4.2.1 Übersicht über die Anwendung ...... 94 5.2.3 Definieren eines eigenen Datentyps ...... 180 4.2.2 Aufbau der ersten Seite ...... 96 5.3 Verwenden von Formatierungen ...... 183 4.2.3 Programmierung von Tabellen ...... 100 5.4 Aggregation Binding ...... 193 4.3 Aufbau eines einfachen Views ...... 102 5.4.1 bindAggregation ...... 198 4.3.1 Namensräume und Ressourcenpfad ...... 103 5.4.2 Verwenden einer Factory ...... 198 4.3.2 Erstellen des JavaScript-Master-Views ...... 105 5.5 Element Binding ...... 204 4.3.3 Erstellen des Master-Controllers ...... 107 5.6 Expression Binding und berechnete Felder ...... 206 4.3.4 Erstellen eines Detail-Views und eines Controllers ..... 111 5.6.1 Berechnete Felder ...... 206 4.4 Typen von Views ...... 117 5.6.2 Expression Binding ...... 209 4.4.1 XML-Views ...... 124 5.7 Ressourcenmodelle und Internationalisierung ...... 210 4.4.2 Transformieren von JavaScript-Views in XML-Views ... 125 5.7.1 Dateispeicherort ...... 210 5.7.2 Dateinamenskonvention ...... 210 5.7.3 Codepage ...... 211 5.7.4 Verwenden eines Ressourcenmodells ...... 212</p><p>8 9 4456.book Seite 10 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 11 Mittwoch, 9. November 2016 10:03 10</p><p>Inhalt Inhalt</p><p>5.8 View-Modelle und das Gerätemodell ...... 216 7.4.3 Erweiternmit $expand ...... 322 5.8.1 Verwenden von View-Modellen ...... 217 7.4.4 Gruppieren mit group ...... 327 5.8.2 Verwenden des Gerätemodells ...... 222 7.5 Paging und Schwellenwerte ...... 328 5.9 Fazit ...... 225 7.6 Batch-Modus ...... 332 7.7 Unidirektionale und bidirektionale Bindungen ...... 334 6 CRUD-Operationen ...... 227 7.7.1 Unidirektionale Bindung ...... 335 7.7.2 Bidirektionale Bindung ...... 338 6.1 Was ist REST? Was ist CRUD? ...... 227 7.8 Schreiben von Daten ...... 341 6.2 Herstellen einer Verbindung zu REST-Services ...... 228 7.8.1 Erstellen eines Eintrags ...... 344 6.2.1 Konfigurieren eines Mock-Service ...... 230 7.8.2 Aktualisieren eines Eintrags ...... 349 6.2.2 Erweitern des JSON-Modells ...... 233 7.8.3 Löschen eines Eintrags ...... 351 6.3 Verwenden von CRUD-Operationen ...... 235 7.9 Funktionsimporte ...... 352 6.3.1 Bearbeiten eines vorhandenen Eintrags ...... 235 7.10 Parallelitätssteuerung ...... 356 6.3.2 Erstellen eines neuen Eintrags ...... 246 7.11 Fazit ...... 359 6.3.3 Löschen eines Eintrags ...... 256 6.4 Sortieren, Filtern und Gruppieren in JSON-Modellen ...... 259 8 Anwendungsmuster und -beispiele ...... 361 6.4.1 Sortieren ...... 259 6.4.2 Filtern ...... 264 8.1 Layouts ...... 362 6.4.3 Gruppieren ...... 271 8.1.1 Full-Screen-Layout – sap.m.App ...... 367 6.5 Fazit ...... 274 8.1.2 Split-Screen-Layout – sap.m.SplitApp ...... 370 8.2 Floor-Plans ...... 374 7 Einsatz von OData ...... 277 8.2.1 Arbeitsvorrat ...... 374 8.2.2 Master-Detail ...... 383 7.1 OData auf einen Blick ...... 278 8.3 Weitere Anwendungsfunktionen ...... 394 7.1.1 Northwind-OData-Service ...... 278 8.3.1 notFound-Behandlung ...... 395 7.1.2 Servicedokument ...... 280 8.3.2 Fehlerbehandlung ...... 400 7.1.3 Servicemetadatendokument ...... 281 8.3.3 Busy-Handling ...... 402 7.1.4 Zugreifen auf Daten ...... 283 8.3.4 Letterbox-Format ...... 405 7.2 OData-Modell auf einem Blick ...... 289 8.3.5 Kopf- und Fußzeilen ...... 407 7.2.1 Servicemetadaten ...... 291 8.4 Ausführen von Anwendungen im SAP Fiori Launchpad ...... 409 7.2.2 Instanziieren des OData-Modells in der 8.4.1 SAP Fiori Launchpad Sandbox ...... 410 SAP Web IDE ...... 292 8.4.2 Anwendungsübergreifende Navigation ...... 415 7.3 Lesen der Daten ...... 296 8.4.3 Registrieren und Ausführen im Produktivsystem ...... 416 7.3.1 Manuelles Lesen der Daten ...... 296 8.5 SAP-Fiori-Referenz-Apps ...... 420 7.3.2 Zugreifen auf Daten über Data Binding ...... 300 8.5.1 Manage-Products-App ...... 420 7.3.3 Best Practices ...... 304 8.5.2 Shop-App ...... 422 7.3.4 Anzeigen zusätzlicher Produktinformationen ...... 309 8.6 Fazit ...... 423 7.3.5 Anzeigen der Navigationseigenschaften ...... 311 7.4 Filtern, Sortieren, Erweitern und Gruppieren ...... 313 9 Weiterführende Konzepte ...... 425 7.4.1 Filtern mit $filter ...... 314 7.4.2 Sortieren mit $orderby ...... 319 9.1 Schreiben eigener Controls ...... 425 9.1.1 Struktur der Controls in SAPUI5 ...... 426</p><p>10 11 4456.book Seite 12 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 13 Mittwoch, 9. November 2016 10:03 10</p><p>Inhalt Inhalt</p><p>9.1.2 Implementieren eines zusammengesetzten Controls ... 433 11.2 Schreiben von Unit-Tests ...... 529 9.2 Verwenden von Fragmenten ...... 443 11.2.1 Einrichten einer QUnit-Testseite ...... 531 9.2.1 Erstellen von Fragmenten ...... 444 11.2.2 Schreiben eines Unit-Tests für eigene Controls ...... 533 9.2.2 Integrieren von Fragmenten in Views ...... 447 11.2.3 Unit-Tests für Apps ...... 539 9.2.3 Verwenden von Dialogen in Fragmenten ...... 452 11.3 One-Page-Acceptance-Tests ...... 547 9.3 SAP-OData-Annotations ...... 456 11.3.1 Architektur ...... 548 9.3.1 Benutzerdefinierte SAP-OData-2.0-Annotations ...... 456 11.3.2 OPA-Teststruktur ...... 548 9.3.2 OData-4.0-Annotations ...... 458 11.3.3 Schreiben von waitFor-Funktionen ...... 549 9.4 Smart Controls ...... 460 11.3.4 Schreiben von OPA-Tests ...... 554 9.4.1 Smart Tables und Smart Filter Bar ...... 465 11.3.5 Behandlung des Anwendungslebenszyklus ...... 560 9.4.2 Smart Form und Smart Fields mit Wertehilfe ...... 468 11.3.6 Strukturieren von Tests mit Seitenobjekten ...... 561 9.5 Smart Templates ...... 469 11.3.7 Vollständige Einrichtung von Anwendungstests ...... 562 9.6 Fazit ...... 473 11.4 Simulieren von Daten mit dem Mock-Server ...... 567 11.4.1 Grundlegende Instanziierung und Konfiguration ...... 567 11.4.2 Erweiterte Konzepte und Konfiguration ...... 568 TEIL III Der letzte Schliff 11.5 Linting-Code ...... 572 11.6 Fazit ...... 575 10 Enterprisetaugliche Anwendungen erzeugen ...... 477</p><p>10.1 Themes erstellen ...... 477 12 Was Sie nicht tun sollten ...... 577 10.1.1 Manuelle Formatierung ...... 479 12.1 Worst Practices ...... 577 10.1.2 UI Theme Designer ...... 482 12.1.1 Komplett verkorkste Anwendungsformatierung ...... 578 10.2 Sicherheit ...... 489 12.1.2 Ignorieren der allgemeinen Regeln in der SAPUI5- 10.2.1 Eingabevalidierung ...... 489 Anwendungsentwicklung ...... 581 10.2.2 Cross-Site Scripting ...... 489 12.1.3 Performance negativ beeinflussen ...... 583 10.2.3 URLs und Filtern mit Positivliste ...... 490 12.2 So machen Sie Ihre Apps bei Updates funktionsunfähig ...... 584 10.2.4 frameOptions und zentrale Positivlisten ...... 491 12.2.1 Verwenden von privaten und geschützten Methoden 10.3 Performance ...... 492 oder Eigenschaften in SAPUI5 ...... 584 10.3.1 Bündeln und Vorabladen der Komponente ...... 493 12.2.2 Verwenden von veralteten oder experimentellen APIs 585 10.3.2 Minifizierung und Uglity-Prozess ...... 493 12.2.3 Erweitern von SAPUI5-Controls ...... 585 10.4 Barrierefreiheit ...... 508 12.3 Fazit ...... 586 10.4.1 Bedeutung von Inklusion und Barrierefreiheit ...... 508 10.4.2 Barrierefreiheitsfunktionen in SAPUI5 ...... 512 Anhang ...... 587 10.4.3 Barrierefreiheit für Anwendungen ...... 515 10.5 Fazit ...... 517 A IDE-Einrichtung ...... 589 B Zugriff auf das Backend ...... 615 11 Debuggen und Testen von Code ...... 519 C Deployment von Anwendungen ...... 631 D Cheat Sheets ...... 665 11.1 Debuggen ...... 520 E Weitere Ressourcen ...... 679 11.1.1 Hilfreiche Tricks ...... 520 F Das Autorenteam ...... 685 11.1.2 Unterstützende Tools zum Debuggen ...... 523 Index ...... 687</p><p>12 13 4456.book Seite 687 Mittwoch, 9. November 2016 10:03 10</p><p>Index</p><p>_onDisplay 249 Annotation (Forts.) _onObjectMatched 249 Smart Template 469 _onRouteMatched 249 annotationsLoaded 56 @sapUiDarkestBorder 481 Anwendung /UI5/UI5_REPOSITORY_LOAD 652 Architektur 49 Deployment 657 Barrierefreiheit 515 $expand 322, 324, 325, 326 Einstellungen migrieren 157 XML-View 326 Formatierung 578 $filter 314 Funktion 394 $orderby 319, 320, 328 funktionsunfähige 584 $skip 329 Lebenszyklusbehandlung 560 $top 328, 329, 331 Manage-Products-App 420 Muster 361 Start 665 A Template 648 Verzeichnisstruktur 52 ABAP View 150 Backend 648 Anwendungsdeskriptor 49, 94, 103, Deployment 653 155, 159, 304 Repository 652 anwendungsübergreifende Navigation Server 651 Handler 416 ABAP Workbench 655 Ziel 416 Abhängigkeit 52, 233, 543 API 427 Access-Control-Allow-Origin 683 Control 81 addAggregationName 78 Dokumentation 28 addButton 77 experimentelle 585 addStyleClass 578 filtern mit Positivliste 490 adressierbar 457 Klasse 57 Advanced REST Client 684 OData-Modell-Dokumentation 57 Aggregation 76, 81, 428, 566 SAP Fiori Launchpad 410 hidden 436 sap.ui.Device 365 Kardinalität 78 veraltete 585 sortieren 259 App 28 Standard 195, 196, 430 Application Descriptor 598 Tabelle 202 AppModel 234, 244, 247, 250, 254 untergeordnetes Control hinzufügen 76 Arbeitsvorrat 374 zu Control-Metadaten hinzufügen 429 Anzahl an Objekten 377 Aggregation Binding 129, 193, 194, 209 Detail-View 379 Factory 198 Filterfunktion 378 Aktion 407, 553 Navigation 379 aktualisierbar 457 sap.m.Table 376 Analysis Path Framework (APF) 36 Sucheingabe 378 AnalyticalTable 44 Tabelle 375 <a href="/tags/Angular_(web_framework)/" rel="tag">Angular</a> 38, 606 View 383 Annotation 459 Architektur 43, 49 OData 2.0 456 Array.prototype.splice 257 OData 4.0 458, 459 Assertion, Art 529 Smart Control 460 Assoziation 76, 78, 81, 277, 282, 430</p><p>687 4456.book Seite 688 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 689 Mittwoch, 9. November 2016 10:03 10</p><p>Index Index</p><p>Asynchronous Module Definition Bibliothek (Forts.) ComponentContainer 50 createContent 106, 145 (AMD) 108 sap.ushell 45 ComponentLauncher 557, 560 Cross-Origin Resource Sharing (CORS) Atom 589 sap.uxap 45 Component-preload.json 505, 506 235, 617 attachInit 665, 666 sap.viz 44 config 148 Cross-Site Scripting (XSS) 489 Aufrufbehandlung 404 bidirektionale Bindung 334, 338 console.log() 63 CRUD 277, 421, 541 auslagerbar 457 Controller 340 Content Delivery Network (CDN) Eintrag löschen 256 manifest.json 338 24, 656 neuen Eintrag erstellen 246 View 339 Control 25, 27, 75 Operation 227, 235, 280 B Bildschirmgröße 30 Aggregation 76, 428 vorhandenen Eintrag bearbeiten 235 bindAggregation 198, 203, 672 Anzahl 25 CSS 578 Backend bindElement 153, 205, 219, 672 API 81 eigenes 479, 517 Destination 623 bindingContext 219 Assoziation 78 Klasse 83 Zugriff 615 bindingMode 223 Bildsteuerung 69 Zugriff und Verbindung 293 bindItems 100 Bindung 171 bAdd 270 bindProperty 56, 171, 173, 176, 183, Cheat Sheet 676 D Barrierefreiheit 33, 508 208, 673 DOM-Referenz 668 alternativer Text und QuickInfo 516 Bindung eigenes 535 Data Binding 27, 161, 165, 451, 672 Beschriftung 515 bidirektionale 334, 338 eigenes schreiben 425 Datenzugriff 300 Farbe 517 unidirektionale 335 Eigenschaft 428 Informationen abrufen 673 Funktion 508, 512 Bindungspfad einfaches 69 manuelles 672 gesetzliche Vorschriften 512 absoluter 302, 304 Einstellung 171 unidirektionales und bidirektionales 334 Größe 517 relativer 303 Einstellung für PropertyBinding 171 Data.json 143 Rolle 515 bindView 205 erweitern 585 DataBinding 100, 118, 161 Tastaturbedienung 514 Blättern 218 Grundgerüst 426 datajs 34 Titel 516 Body 665 in der Anwendung verwenden 442 data-sap-ui-libs 68 Vorteil 511 Bookmarking 410 komplexes 76, 78 data-sap-ui-theme 68 Batch Bootstrapping 67, 412, 532, 665 Layout 82 Daten Antwort 334 Breakpoint 526, 527 Lebenszyklusmethode 431 laden 162 Modus 332, 333 browserübergreifende Kompatibilität 29 Lokalisierung 33 lesen 296, 670 Request 333 Bündelung 493 Metadaten 427 manuell lesen 296, 297 batchRequestCompleted 56 BusinessPartnerNotFound 396 Reaktionsfähigkeit 32 Navigation 286 Bearbeitungsbehandlung Busy-Handling 402, 404 Renderer 441 schreiben 341, 670 allgemeine 405 Master-Detail 405 rendern 432 Typ 175, 176 Aufruf von Metadaten 403 busyIndicatorDelay 403 sap.m.Button 28 Zugriff 283 für einzelne Controls 404 bypassed 399 Struktur 426 Zugriff über Data Binding 300 Behandlung von Suchen 379 übergeordnetes 76 Daten simulieren 567 Beispieldaten 231 Unit-Test für eigenes Control 533 Datentyp Bibliothek 25, 43 C untergeordnetes 76 Ausnahme 177 sap.m 44, 68, 76 Vererbung 53 Definition 182 sap.m.List 332 catchAll 399, 400 Verhalten 431 eigener 180 sap.suite 45 Change-Handler 438 zusammengesetztes 433 Funktion 176 sap.ui.base 53 Cheat Sheet 665 Controller 47, 91, 92 Debuggen 116, 133, 519, 520 sap.ui.commons 45 Code, Formatierung 64 bearbeiten 245 unterstützendes Tool 523 sap.ui.comp 45 Codevervollständigung 589, 599, Code der Formatierung 184 YouTube-Tutorial 522 sap.ui.core 43, 44, 53 606, 609 Detail 111, 258 Deep Link 386, 388, 389, 396 sap.ui.layout 44, 202 Coding Edit-View 243 defaultSpan 85 sap.ui.richtexteditor 45 Einrichtung 66 Konvention 116 deferred 300 sap.ui.suite 45 Konvention 674 Lebenszyklus 48 deleteEntry 257 sap.ui.table 44 Richtlinie 61 Lebenszyklusmethode 153 Demokit 26 sap.ui.unified 44 CommonJS 108 Master 107 Deployment 631 sap.ui.ux3 45 Component preload 119, 504, 505 testen 542 ABAP-Server 651 sap.ui.vk 45 Component.js 94, 146, 159, 305, 610 CORS 618 SAP HANA Cloud Connector 641</p><p>688 689 4456.book Seite 690 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 691 Mittwoch, 9. November 2016 10:03 10</p><p>Index Index</p><p>Deployment (Forts.) ESLint 64, 573, 574, 575 Fragment (Forts.) Gruppieren 271, 272, 327, 328 SAP HANA Cloud Platform 631 Etag 356, 357, 358 Lazy Loading 449, 454 Benutzereingabe 273 SAP Web IDE 641 Event-Handler 69, 71, 74, 385 SimpleForm 444 Button 273 Descriptor Editor 381 einfacher 71 Suffix 444 erstes 272 Desktop-PC 30 Explored-App 27, 30, 406 XML-View 448 Smart Table 464 Destination Expression Binding 206, 209, 309 frameOptions 491 Gulp 495, 606 einfaches Backend 623 Ext.js 39 Framework, geräteunabhängiges 29 Northwind 627 Full-Screen-Layout 362, 367, 369 Detail-Controller 111, 112, 114, 153 Arbeitsvorrat 374 H detailPages 370 F Richtlinie 367 Detail-View 111, 112, 113 Routingkonfiguration 368 Hello, SAPUI5 World 61 Dialog 453 Factory 198, 449 Funktion, anonyme 72 Herkunft 615 div 82 FakeRest 230, 232 Funktionsimport 352 HideMode 373 Dokumentation 679 herunterladen 231 Controller 355 HTML 29, 102, 117 DOM Farbe 517, 578 View 354 Fragment 443 Abstraktion 529 Farbpalette 478 Fußbereich 408 Startseite 67 Attribut 65 Fehler 400 Fußzeile 407 View 123 Element 579 Antwort 401 HTTP-Request 496 Manipulation 34 Behandlung 395, 400 Benachrichtigung 401 G Feld, berechnetes 206, 207, 208 I E Filter 264, 314, 378 Gerätemodell 216, 222 anwenden und aufheben 267 Bindung 224 i18n 374 Eclipse 589 eigener 266 Implementierung 223 i18n_de_AT.properties 211 eigener Datentyp 180 Operation 267 instanziieren 224 i18n_de.properties 211 Eingabevalidierung 489 zur Bindung hinzufügen bzw. daraus Geschäftsanwendung 477 i18n_en_GB.properties 211 eingebettetes HTML 118 entfernen 271 getMetadata 54 i18n_en.properties 211 Eintrag Filtern getObject 56 i18n.properties 211 aktualisieren 349 Einzelpreis 314 getProperty 81, 167, 170 ID 99, 134 erweitern 322 JSON-Modell 259 GET-Request 229 iFrame 491 löschen 351 Master.controller.js 318 Getter 81 index.html 91, 95 Element Master.view.xml 318 Getter-Methode 669 Inhaltsbereich 367 globales 667 mit Positivliste 490 GitHub 230, 433 Inklusion 508 ID 666 mit Positivliste, API 490 GitHub-Repository 682 Innenabstand 482 im Controller 667 Smart Filter 466 Git-Repository 631 Integration 562 referenzieren 666 Smart Tables 463 globale Variable 62 Internationalisierung 210 Element Binding 204 Floor-Plan 374 Google Chrome Entität Arbeitsvorrat 374 Entwicklertool 521 lesen 285 Master-Detail 383 Entwicklertools 167 J Typ 277 Master-Detail-Muster 370 Plug-in 683 Entitätsmenge 279, 281 fnTest 265 Web Security deaktivieren 620 JavaDoc 675 lesen 284 Formatierung 180, 183, 184, 187, 189, growing 330 JavaScript 29, 34, 62, 117, 681 Metadaten 282 192, 208 growingScrollToLoad 332 Aggregation Binding 194 Entwicklerhandbuch 76 nicht anonym 184 growingThreshold 330, 332 Fragment 443 Ereignis 74, 75, 431 formatOptions 179 growingTriggerText 332 globale Variable 62 press 72 formatValue 177 Grunt 495, 606 Master-View 105, 127 requestSent 164 Fragment 425, 443, 445, 493 ausführen 504 Playground 682 überwachen 669, 671 Daten anzeigen 446 Einrichtung 497 Programmierrichtlinie 674 Ereignis-Listener 117 Definition 444 globale Installation 497 Versprechen 390 error-Handler 297 Dialog verwenden 452, 453 Minifizierung 498 View 102, 105, 122 Erweiterung 425 erstellen 444 Gruntfile.js 498, 499, 501 XML-View 125 es4-Demo-Gateway-Destination 628 in View integrieren 447 grunt-<a href="/tags/OpenUI5/" rel="tag">openui5</a> 495, 502</p><p>690 691 4456.book Seite 692 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 693 Mittwoch, 9. November 2016 10:03 10</p><p>Index Index</p><p>JAWS 509 Layout 82, 362 Methode (Forts.) Navigation (Forts.) JetBrains 589, 606 Control 82, 85 private 584 anwendungsübergreifende 379, Journey 563 Full-Screen-Layout 367 Mikro-Controller 496 410, 415 jQuery 34, 529 sap.m.App 367 Minifizierung 493, 494, 501 Navigationseigenschaft 277, 280, 282 jQuery.sap.declare 63 sap.m.SplitApp 370 grunt-basierter Task Runner 495 anzeigen 311 jQuery.sap.resources 216 Split-Screen-Layout 370 SAP Web IDE 506 Bindung 312 JSBin 682 LayoutData 85 Mock-Daten, Instanziierung und zurück 397 JSDoc 81, 675 Leave-Request-Management-App 35 Konfiguration 567 navTo 237 JSFiddle 682 Lesezeichen 146 Mock-Server 460, 567, 569, 603 neo-app.json 293 JSON 29, 102, 117, 162, 233 Letterbox-Format 139, 140, 141, erweitern 571 Network, Trace 618 Beispielanwendung 166 405, 406 erweiterte Konzepte und Netzwerk Instanziieren des Modells 162 Lifecycle Hook 48 Konfiguration 568 Datenverkehr 111 Modell 163, 259 Linting 572 Grundgerüst 570 Request 296 sortieren und filtern 259 List Binding 175 Instanziierung und Konfiguration 567 Netzwerk-Request, optimierter 505 Tool 683 Live-Wert 173 Steuerungsoption 570 Node.js 495 View 123 loadData 163, 164, 167 Mock-Service 228, 230, 231, 232 Einrichtung 496 JSON-Modell 233, 246 Lokalisierung 33 Modell 29, 47, 91, 160, 161 Vorteil 496 anlegen 668 löschbar 457 Bindung zwischen Control-Eigenschaft Northwind 283 Ereignis überwachen 669 und Wert 171 Destination 627 Getter- und Setter-Methode 669 Einsatz 162 Notation, ungarische 65, 674 JSONView 683 M Instanziierung und Laden der notFound-Behandlung 395 Daten 162 NPM 606 ManagedObject 54, 79, 81 Knotenpfad 169 Nutzdaten 346, 350 K Manage-Products-App 420 Vererbung 55 GET 347 manifest.json 94, 638 Zugriff auf Wert 165 POST 347 Kardinalität 76 Massive Online Open Courses Modul Kategorie, erweiterte 324 (MOOC) 679 abhängiges 109 Kern 43 Master.controller.js 102 laden 109 O Kettenfunktion 564 Master.view.js 102, 107 Modularisierung 103 Klassenformatierung, interne 579 Master-Controller 107 MVC 29, 91 oberflächenfreie Komponente 135 Klassenhierarchie 52 press-Handler 115 Anwendung 94 ObjectNotFound 397 Kompatibilität Master-Detail 383, 395 Daten und Modell erstellen 98 Objekt-Header 207 browserübergreifende 29 Deep Link 388 Detail-Controller 186 Objektmitglied, privates 63 Komponente 135 Masterliste 384, 386 Detail-View 187 Objekt-View 385 Container 138 mobiles Gerät 392 erste Seite 96 octotree 684 Datei 135 Objekt-View 385 Formatierung 188 OData 55, 162, 163, 277, 681 Konvention 146 Standardroute 391 index.html 95 2.0 456 Metadata 143 Master-Detail-App 484, 498, 499 Komponente 135 2.0-Annotation 456 Shell 139 Master-Detail-Muster 370 Ordnerstruktur 103 4.0 456 Tabelle optimieren 141 Masterliste 387, 399 Struktur 93, 96 4.0-Annotation 458 Konzept, erweitertes 425 masterPages 370 Annotation 456 Kopfbereich 408 Masterseite erstellen 100 anzeigen 280 Kopfzeile 407 Master-View 110, 111, 114, 248 N auf Daten zugreifen 283, 300 press-Handler 115 Best Practices Component.js 306 Matcher 551 Nabisoft 680 Best Practices für App.view.xml 308 L Metadaten 427 Namensraum 103, 104, 124, 442, Best Practices für index.html 309 Aufruf 403 456, 581 Best Practices für manifest.json 307 labelFor 515 Fehler 402 definieren 104 Best Practices für master.view.xml 308 labelSpan 240 metadataLoaded 56 Methode 63 Daten lesen 296 Laden 49 <a href="/tags/Meteor_(web_framework)/" rel="tag">Meteor</a> 606 Navigation Daten schreiben 341 LATIN-1 211 Methode 55 anwendungsinterne 379 erweitern 322 geschützte 584 Expression Binding 309</p><p>692 693 4456.book Seite 694 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 695 Mittwoch, 9. November 2016 10:03 10</p><p>Index Index</p><p>OData (Forts.) OpenUI5 (Forts.) QUnit-Test (Forts.) S filtern 314 To-do-App 682 Seite 531 Funktionsimport 352 Operator Testgrundgerüst 534 Same-Origin Policy 291, 292, 615 für Schreibvorgänge aktiviert 352 Filter 315 SAP Blue Crystal 486 gruppieren 327 logischer 315 SAP Business Suite 45 Klassenvererbung 56 String 315 R SAP Community Network (SCN) Modell 289 optimistische Parallelität, 590, 681 Modell aktualisieren 351 implementieren 356 RadioButtonGroup 76, 77, 78 SAP Developer 680 Modell erstellen 349 oTemplate 101 Rand 482 SAP Fiori 35, 44, 102, 139, 361, 370, Northwind 278, 281 React 38, 606 473, 590 Ordnerstruktur für Best Practices 305 Render Manager 432, 514 App-Bibliothek 680 Parallelitätssteuerung 356 P Renderer 440 Demo Cloud Edition 680 SAP Web IDE 292, 298 Render-Manager 44 Designrichtlinie 361, 369, 676, 681 Schreibunterstützung 342 Package.json 502 Representational State Transfer Implementierung und Entwicklung 681 Shop-App 423 Paging 328, 330 (REST) 227 Manage-Products-App 420 sortieren 319 Parallelität, optimistische 356 requestFailed 245 openSAP-Kurs 679 Übersicht 278 Parallelitätssteuerung 356 requestSent 56 Referenz-App 420, 422, 680 unidirektionale und bidirektionale parseError 178 RequireJS 108 SCN 681 Bindung 334 parseValue 177 Responsive Design 367 Shop-App 420, 422, 423 Ziel 304 patternMatched 388 Ressource SAP Fiori Launchpad 49, 104, 135, 374, OData-Modell Performance 492, 517 Ordner 104 410, 581 anlegen 670 Worst Practice 583 Pfad 103 Anwendung ausführen 409, 416 Ereignis überwachen 671 pessimistische Parallelität 356 weitere 679 Anwendung zuweisen 419 ODBC 278 Phoenix 24 Ressourcenbündel 210, 246 anwendungsübergreifende onAfterRendering 49, 54 Platform as a Service (PaaS) 589, 631 Codepage 211 Navigation 415 onBeforeRendering 49, 54 Plunker 683 Dateibenennung 210 ausführendes Sandbox-Programm in onExit 49 PopoverMode 373 Dateispeicherort 210 der SAP Web IDE 411 onInit 49, 234, 269, 448, 668 Positivliste, Service 491 Ressourcenmodell 210 eigene Sandbox 412 onPress 262 Postman 341, 342, 683 Codepage 211 Kachel einrichten 418 onPressImage 74 Eintrag erstellen 346 Detail-View 214 Katalog 419 onSave 256 Produktinformation 309 instanziieren 213 Navigation 418 OPA5 520, 547, 556 Projekt, Art 640 Verwendung 212 Registrierung 414 Aktion 553 Property Binding 170 REST 227 Rolle 419 Architektur 548 bindProperty 173 Service 227 Sandbox 410 erweitern 559 Control-Einstellung 171 Verbindung zu Servicesherstellen 228 Sandbox initialisieren 413 Matcher 551 Datentyp 175 zustandslos 228 Sandbox-Benutzeroberfläche 411 Mock-Server 569 Formatoption 180 RESTful statische und dynamische Kacheln 418 Ordnerstruktur 563 JSON-Modell 175 Service 227 SAP Gateway 681 Seitenobjekt 562 Prüfung der Dichte der Inhalte 365 RGB-Farbe 481 SAP HANA Cloud Connector 641 Test 554 Purchase-Order-App 35 Rich Internet Applications (RIA) 515 Architektur 641 Teststruktur 548 RichTextEditor 45 Deployment 652 waitFor 551 rootView 160 Einstellung 642 Open Source 34 Q Route bei leerem Muster 391 openSAP-Kurs 646 OpenAjax 62 Routing 27, 146, 149, 380, 391 SAP HANA Cloud Platform 24, 61, 68, openSAP 679 Qualität 572 Behandlung 392 294, 589 Smart Template 473 QUnit 519, 520, 529, 530, 547, 549, Detail-Controller 153, 154 App-Deployment 631 OpenUI5 23, 25, 39, 40, 460 554, 558, 575 Initialisierung 150 Cockpit 592, 632 CDN 663 DOM-Struktur 559 Konfiguration 147, 237, 364, 365, Destination 622 Homepage 680 Konstruktorergebnis 535 371, 373 Destination anlegen 647 openui5_preload 495, 501 QUnit-Test 532 leeres Muster 391 eigenes Theme bereitstellen 488 SDK 606 Datei 533 Master-Controller 151 Konto anlegen 590 Slack Channel 681 Muster 152 Minifizierung 506</p><p>694 695 4456.book Seite 696 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 697 Mittwoch, 9. November 2016 10:03 10</p><p>Index Index</p><p>SAP HANA Cloud Platform (Forts.) sap.m.semantic 407 SAPUI5 Diagnostics 523, 524 Smart Group 468 openSAP-Kurs 679 sap.m.Shell 406 SAPUI5 Flexibility Services 464 Smart Table 461, 465, 467 Same-OriginPolicy 616 sap.m.SplitApp 370, 384 SAPUI5 Technical Information 523 filtern 463 SAP Fiori Launchpad 410, 416 Responsive Design 372 SAPUI5-Demokit 442, 480 geändert 467 Seminar 593 sap.m.SplitAppModes 373 sap-ui-theme 478 gruppieren 464 UI Theme Designer 482, 486 sap.m.Table 94, 198, 375 Schwellenwert 328, 330 hinzufügen, ausblenden, sortieren 463 SAP HANA XS 496 sap.m.Text 184 Seiten-Control 236 Metadaten 462 SAP HANA XS Advanced (XSA) 496 sap.ui 159 Seitenobjekt 561, 564, 565 Personalisierung 462 SAP S/4HANA 102 sap.ui.base.EventProvider 54, 56 gemeinsames 566 sortieren 463 SAP Technology Rapid Innovation Group sap.ui.base.ManagedObject 173 Selektor 580 Smart Template 469, 471 (RIG) 646 sap.ui.base.Object 53, 54, 56 Selenium 547 Anwendung entwickeln 469 SAP Web IDE 61, 235, 293, 363, sap.ui.core 44 Semikolon 64 openSAP 473 589, 641 sap.ui.core.Component 49 Sencha 39 Smart Form 471 Anwendung exportieren 657 sap.ui.core.Control 54 Service Smart Table 470 Anwendungsentwicklung 596 sap.ui.core.Element 54 Dokument 280 Smartphone 30 App-Deployment 631 sap.ui.core.Fragment 668 Fehler 402 Sortieren Backend-Zugriff 293 sap.ui.core.ManagedObject 54 Metadaten 291, 295 Aggregation 259 Descriptor Editor 380 sap.ui.core.message.Message- Metadatendokument 281 Button 262 Einrichtung 589 Processor 56 URL 293 Funktion 263 ESLint 574 sap.ui.core.Model 56 setAggregation 436 JSON-Modell 259 Instanziieren eines OData-Modells 295 sap.ui.core.routing.Router 50 setAggregationName 78 Master.view.xml 320 Konsolenausgabe 654 sap.ui.define 109 setData 163 Smart Table 463 Konsolen-View 654 sap.ui.layout 124 setProperty 81, 167 Tabellenelemente 260 Layout Editor 119 sap.ui.layout.form.SimpleForm 239 Setter 81 sortieren 319 Linting 573 sap.ui.layout.Grid 82 Setter-Methode 669 Sortierung Master-Detail 383 sap.ui.model.odata.ODataModel 289 Shopping-Cart-App 35 eigene 264 Minifizierung 506 sap.ui.model.odata.V2.ODataModel 56 ShowHideMode 373 mehrfache 264 Northwind-Service 297 sap.ui.model.odata.v2.ODataModel 289 Sicherheit 489 sPageId 133 Same-OriginPolicy 616 sap.ui.model.SimpleType 180, 181 Eingabevalidierung 489 Spaltenüberschrift 262 SAP FioriLaunchpadSandbox 411 sap.ui.model.Sorter 274 filtern mit Positivliste 490 Split-Screen-Layout 362, 370 SAP HANA Cloud Connector 645 sap.ui.model.type.Boolean 176 frameOptions 491 Main.view.xml 370 SAP-Fiori-Referenz-App 420 sap.ui.model.type.Date 176 SAPUI5-Richtlinien 492 Master-Detail 383 SAP-HCP-Destination 624 sap.ui.model.type.DateTime 176 URL validieren 490, 491 Sprache 215 SCN 681 sap.ui.model.type.Float 176 zentrale Positivliste 491 Ermittlung 215 UI Theme Designer 482, 487 sap.ui.model.type.Integer 176 Sichtbarkeit 578 Fallback zur Ermittlung 211 Vorlage 595 sap.ui.model.type.String 176 sight 684 Spy 540 ZIP-Datei speichern 658 sap.ui.model.type.Time 176 SimpleForm 239, 240, 313, 442 src 68, 81, 665 Zugriff 593 sap.ui.namespace 63 Fragment 444 StretchCompressMode 373 SAP Service Marketplace 24 sap.ui.require 109 Simulieren string 117 sap.m 124, 159 sap.ui5 160 einzelne Antwort 572 Struktur, hierarchische 168 sap.m.App 130, 367 SAP-Smart-Business-Cockpit 35 Zeitangabe 545 Stub 540, 544 sap.m.CheckBox 55 SAPUI5 23 sinon 231, 539, 542 Sublime 589 sap.m.Checkbox 265 Anwendungsfall 35 sLocalPath 256 Symbol 28 sap.m.Dialog 103, 453 Architektur 43 Smart Control 425, 460 sap.m.Input 172 CDN 656 Information 468 sap.m.Label 515 Datentyp 176 Tutorial 465 T sap.m.List 390 Demokit 26 Smart Field 468 sap.m.MessageBox 400 Entstehung 24 Smart Filter 465 Tabelle sap.m.MessagePage 396 Funktionen 25 Smart Form 468 erstellen 100 catchAll 400 Open Source 34 Bearbeitungsmodus 468 Komponente 141 sap.m.Page 112 Produktvergleich 38 Smart Template 471 Programmierung 100 sap.m.PullToRefresh 394 Überblick und Zugriff 23 Wertehilfe 469 reaktionsfähiger Rand 142</p><p>696 697 4456.book Seite 698 Mittwoch, 9. November 2016 10:03 10 4456.book Seite 699 Mittwoch, 9. November 2016 10:03 10</p><p>Index Index</p><p>Tabelle (Forts.) UI5 Inspector 301, 523, 528, 683 WebSockets 496 XML (Forts.) sortieren und gruppieren 273 UI5con 2016 682 WebStorm 589, 606, 613 View 102, 118, 119, 122, 123, 124, Überschrift 101 UI-Komponente 135 Einrichtung 613 126, 448 Zeile 102 unbindElement 206 Version 607 XmlHTTPRequest 232 Tablet-Bildschirm 30 unbindProperty 198 Whitelist 490 XMLHttpRequest, simulierter 541 Task Runner 495 unidirektionale Bindung 161, 334, 336 Workitem 374 XOData 278, 343, 683 Template 650 Controller 337 Worklist-App 600 Tern.js 589 Unit-Test 529, 603 Mock-Daten 603 Testen 519, 544, 545, 546 App 539 Worldwide Web Consortium (W3C) 512 Z Callback-Funktion 540 eigenes Control 533 Worst Practice 577 Double 540 Ergebnis 530 writeEscaped 489 Zeitangabe, simulierte 541 Element 531 Setter-Methode 538 Ziel 149, 293, 381 Konstruktorergebnis 535 untypisierte Variante 174 zusammengesetztes Control 433 Seitenobjekt 561 URL, servicebasiert 284 X Abhängigkeit definieren 434 Setter-Methode 537 Konstruktor 435 Strategiepyramide 519 XML 29, 102, 117 Methode und Ereignis 437 vollständige Einrichtung für V Fragment 443 Mitglieds-Control instanziieren 435 Anwendungen 562 JavaScript-Ansicht 125 Renderer 440 Textrichtung 582 validateValue 177 Knoten 285 Struktur, Metadaten und Theme 32, 477 Variable Tool 683 Abhängigkeiten 433 Auswahl 484 globale 62 Basis 478 Namenskonvention 65 eigene CSS 479 nicht deklarierte 63 High-Contrast Black 480, 513, 517 VerticalLayout 202 manuelle Umformatierung 479 Verzeichnis 52 Parameter 481 View 29, 47, 91, 92 theme-abhängige CSS-Klasse 481 Anzeigemodus 450 Theme-Parameter 580 Detail 111 Transaktion erstellen 102 SE38 658 Fragment integrieren 447 SE80 655, 661 Instanziierung 48 Tutorial 27 Konvention 125 Typ, komplexer 343 Typ 117 View-Modell 216, 217, 221 Bindung 219 U instanziieren 218 Navigationsfunktion 222 Überlauf 407 Vokabular 462 Übersetzen 581 Vorabladen der Komponente 493 Überspringen 329 Vorlage 102, 118, 363, 366 Übertreiben 579 Uglification 493, 494 UglifyJS 494 W UI Development Toolkit für HTML5 23 UI Theme Designer 32, 440, 481, 482 waitFor 549, 566 eigenesTheme 486 Konfiguration 554 Einrichtung 483 Was Sie nicht tun sollten 62 Quick-Modus 484 Web Accessibility Initiative (WAI) SAP Web IDE 487 512, 680 SAP-HANA-Cloud-Platform- Webserver 631, 662 Abonnement 483 Websicherheit 620 Theme bearbeiten 483</p><p>698 699 SAP-Wissen aus erster Hand.</p><p>Christiane Goebels ist Senior-Software-Entwicklerin bei SAP. Sie hatte ihr erstes Webentwicklungsprojekt 2001. Seitdem hat sie an Dutzenden großen und kleinen Webanwendungen für SAP, SAP-Kunden und – in ihrem eigenen Internet-Startup von 2005 bis 2010 – für Kunden ohne Bezug zu SAP gearbeitet. Sie ist eine erfahrene Dozentin und Trainerin für SAPUI5 und OpenUI5 sowie andere webbezogene Themen.</p><p>Denise Nepraunig ist Software-Entwicklerin bei SAP in Walldorf, wo sie SAPUI5-Apps entwickelt und an der Entwicklung von SAP Web IDE beteiligt war. Denise ist eine erfahrene Sprecherin und SAPUI5-Coach und seit kurzem SAP-Mentorin. Sie liebt es, neue Technologien zu erforschen und experimentiert in ihrer Freizeit mit SAP HCP und SAP HANA.</p><p>Thilo Seidel baute seine erste Webseite 2002 und verliebte sich direkt. Seitdem hatte er verschiedene Aufgaben, unter anderem im Vertrieb, als Designer, Denkender, Reisender, Student und Projektmanager. Thilo ist an Werktagen der Pro- duct Owner des SAP Fiori Launchpad, am Wochenende ist er manchmal als Hacker unterwegs.</p><p>Wir hoffen sehr, dass Ihnen diese Leseprobe gefallen hat. Sie dürfen sie gerne emp- fehlen und weitergeben, allerdings nur vollständig mit allen Seiten. Bitte beachten Christiane Goebels, Denise Nepraunig, Thilo Seidel Sie, dass der Funktionsumfang dieser Leseprobe sowie ihre Darstellung von der SAPUI5 – Das umfassende Handbuch E-Book-Fassung des vorgestellten Buches abweichen können. Diese Leseprobe ist in all ihren Teilen urheberrechtlich geschützt. Alle Nutzungs- und Verwertungs- 699 Seiten, gebunden, November 2016 rechte liegen beim Autor und beim Verlag. 79,90 Euro, ISBN 978-3-8362-4456-5</p><p> www.sap-press.de/4303 Teilen Sie Ihre Leseerfahrung mit uns!</p> </div> </article> </div> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script> var docId = '313d62575e8efe56a09ea2adae9367c9'; var endPage = 1; var totalPage = 51; var pfLoading = false; window.addEventListener('scroll', function () { if (pfLoading) return; var $now = $('.article-imgview .pf').eq(endPage - 1); if (document.documentElement.scrollTop + $(window).height() > $now.offset().top) { pfLoading = true; endPage++; if (endPage > totalPage) return; var imgEle = new Image(); var imgsrc = "//data.docslib.org/img/313d62575e8efe56a09ea2adae9367c9-" + endPage + (endPage > 3 ? ".jpg" : ".webp"); imgEle.src = imgsrc; var $imgLoad = $('<div class="pf" id="pf' + endPage + '"><img src="/loading.gif"></div>'); $('.article-imgview').append($imgLoad); imgEle.addEventListener('load', function () { $imgLoad.find('img').attr('src', imgsrc); pfLoading = false }); if (endPage < 5) { adcall('pf' + endPage); } } }, { passive: true }); if (totalPage > 0) adcall('pf1'); </script> <script> var sc_project = 11552861; var sc_invisible = 1; var sc_security = "b956b151"; </script> <script src="https://www.statcounter.com/counter/counter.js" async></script> </html>