JSON Model – Stärken, Schwächen und Anwendung

In der SAPUI5-Entwicklung kommt man nicht um hin, sich an irgendeinem Zeitpunkt mit JSON auseinanderzusetzen. JSON steht kurz für JavaScript Object Notation und bietet eine einfache, standardisierte, textbasierte Darstellung von Objekten.
In der SAPUI5-Entwicklung ist das JSON-Model eins von zwei zentralen Models für die Datenhaltung. (ODataModel ist das andere). Als client-side Model stellt es Daten zur Verfügung, die für die Anwendung zu jeder Zeit komplett verfügbar sind.

Da die Beschreibung des JSON Models in der API des SAPUI5 Demo Kits recht dürftig ist (“Model implementation for JSON format”) will ich euch hier einen tieferen Einblick in das Model geben, sowie Stärken, Schwächen, Anwendungsbereiche und No-Gos ans Herz legen.

Das Arbeiten mit einem JSON Model ist deutlich einfacher und unabhängiger von der Backend-Implementierung als das Arbeiten mit einem ODataModel, weshalb es Frontend-Entwickler dazu verleiten kann, dies auch eher zu nutzen. So ist zumindest meine Erfahrung und, mit Einblick auf Entwicklungen von anderen Entwicklern, bin bzw. war ich da nicht allein.
Das ist aber nicht immer sinnvoll.

Im Folgenden werde ich darauf eingehen, wann es für mich Sinn macht ein JSON Model zu nutzen und wann aber auch nicht. Fangen wir aber mit etwas Einfachem an:

Syntax und Aufruf

Das JSON-Model befindet sich in dem Namespace „sap.ui.model.json“ und lässt sich wie folgt initialisieren:

var oModel = new sap.ui.model.json.JSONModel(oData);

In dem Konstruktor-Aufruf gibt es einen Parameter oData. Dieser kann zwei ganz unterschiedliche Sachen darstellen:

  • Eine URL, von der aus das JSON geladen werden soll
  • Ein JSON-Objekt

Bei beiden Aufrufen wird ein JSON-Objekt in das JSON-Model geladen. Dieses kann anschließend wie gewohnt über ein Binding oder mit der Methode oModel.getData() genutzt bzw. ausgegeben werden.
Gleichermaßen können über die Methode oModel.setData(oData) neue Daten in das JSON-Model geschrieben werden. Interessanterweise kann hier einzig ein JSON-Objekt als Parameter übergeben werden. Für die Variante mit einer URL gibt es den Aufruf oModel.loadData(oData)

Stärken und Anwendungsbereiche

In meinen Anwendungen nutze ich JSON Models für genau drei Anwendungsfälle

  • ViewModels
  • Auswahllisten mit einer geringen Anzahl von Einträgen (z.B. für Select-Boxen)
  • Interaktion mit Dialogen

Eingesetzt als ViewModel speichere ich Einstellungen eines Views in einem eigenen Model. Klassisch für meine Anwendungen ist z.B. eine Eigenschaft „mode“, die beschreibt, ob ich mich im Ansichts- oder im Bearbeitungsmodus befinde. Durch das Setzen dieser Eigenschaft in einem ViewModel kann ich die Controls bzw. deren Eigenschaften (enabled, visible, etc.) sehr einfach über Expression Bindings steuern.

Setzen des ViewModels in der onInit
...
onInit: function(oEvent) {
	...
	this.setModel(new sap.ui.model.json.JSONModel({
		mode: "view",
		busy: false,
		filterActive: false
	}), "viewConfig");
	...
}
...
Steuerung über Expression Bindings
...
<Button icon="sap-icon://edit" press="onEdit" text="Bearbeiten"
	enabled="{= ${viewConfig>/mode} === 'view'}">
...

Wenn du dich näher dafür interessiert kannst du dir auch einfach mal das Entwurfsmuster MVVM näher angucken.

Hinweis: Wenn du das ViewModel onInit setzt musst du darauf achten, dass beim Navigieren das Model zurückgesetzt wird. Sonst können unerwünschte Effekte auftreten.

Der zweite Anwendungsbereich sind die Auswahllisten. Diese erzeuge ich meist beim Starten der Anwendung. Hier achte ich darauf, dass die Anzahl der Einträge auf eine kleine Zahl beschränkt bleibt. Als groben (aber keinesfalls fest definierten) Wert nehme ich mir 20 Einträge als Limit. Alles, was darüber hinaus geht, sollte man meiner Meinung nicht initial Laden sondern anders handhaben.
Meist sind dies Listen, die ich über Function Imports lade, die ich oft benutze und nicht an jeder Stelle neu laden möchte oder die aus anderen Gründen immer vorrätig sein müssen.

Laden einer Auswahlliste in der model.js
...
createMatStatusModel: function(oComponent) {
	var dfdResult = jQuery.Deferred();
	var mOptions = {
		method: "GET",
		urlParameters: {
			"tabname": "TVMST",
			"keyField": "VMSTA",
			"valueField": "VMSTB",
			"sqlWhere": ""
		},
		success: function(oData) {
			oComponent.getModel("matStatusModel").setData(oData.results);
			dfdResult.resolve("fine");
		},
		error: function() {
			oComponent.getModel("matStatusModel").setData([]);
			dfdResult.resolve("fine");
		}
	};

	oComponent.getModel("generalService").callFunction("/getKeyValues", mOptions);

	return dfdResult.promise();
}
...
Aufruf in der Component.js
...
models.createMatStatusModel(this).done(function() {
	this.getRouter().initialize();
}.bind(this));
...

Hinweis: Mit den Deferred Objects stelle ich sicher, dass das Laden der Liste vor dem Start der Anwendung abgeschlossen ist. Der asynchrone Call muss an dieser Stelle berücksichtigt werden.

Zu guter Letzt bleibt der Einsatz im Dialog-Handling. Oftmals nutze ich Eingabedialoge, die auf keine vorhandene Struktur passen oder generische Dialoge, die ich an unterschiedlichen Stellen einsetze. Um einfach Daten, Texte o.Ä. an den Dialog zu übergeben bzw. Daten aus Eingabefeldern des Dialogs auszulesen nutze ich JSON Models.
Dieser Einsatz ist ähnlich dem Einsatz des ViewModels. Diesmal ist das Model aber auf den Dialog beschränkt und, viel wichtiger, hält Daten jenseits von Einstellungen oder Zuständen.

Öffnen eines Dialogs mit einem JSON Model
...
onOpenDialog: function() {
	if (!this._dialog) {
		this._dialog = sap.ui.xmlfragment("acando.blog.view.dialogs.infoDialog", this);
		this.getView().addDependent(this._dialog);
	}
	
	this._dialog.setModel(new sap.ui.model.json.JSONModel({
		"titleLabel" : "Dialogtitel",
		"inputValue" : ""
	}), "dialogData");


	this._dialog.open();
}
...
Dialog Fragment
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core">
	<Dialog title="{dialogData>/titleLabel}">
		<content>
			<Label text="Eingabe Input-Control" />
			<Input value="{dialogData>/inputValue}" />
			...
		</content>
		...							
	</Dialog>
</core:FragmentDefinition>

Schwächen und No-Gos

Wie schon anfangs angedeutet ist das JSON Model ein client-side Model. Es macht somit keine eigenen Backend-Calls und kann aus diesem Grund nur mit den Daten arbeiten, die es im Bauch hat. Aus diesem Grund ist es für die CRUD-Methoden nicht geeignet.
Nun lässt sich ein JSON Model trotzdem zum Daten-Handling umfunktionieren. Es funktioniert auch einigermaßen aber so richtig toll ist es nicht. Meine Empfehlung ist aber ganz eindeutig:

Kein Daten-Handling mit JSON Models

Das Daten-Handling sollte sich immer mit ODataModels umsetzen lassen. Wenn man denkt, dass dies auf Grund der Anforderungen nicht möglich ist sollte man immer überlegen, ob man

  • nicht doch auf irgendeine Art das ODataModel nutzen kann
  • die Anforderungen ändern/vereinfachen kann

Diejenigen, die die Anwendung im Anschluss warten sollen, werden es euch danken.
Darüber hinaus gibt es noch einen Punkt, den ich euch wärmstens ans Herz legen möchte:

Kein create- oder update Deep

create- und update Deep, also Speichern von Strukturen mit mehreren Ebenen (Navigations), ist schlechte Programmierung. Sie ist fehleranfällig, komplex und sehr schlecht wartbar. Mein Rat auch hier: Macht es nicht. Und meine Erfahrung an dieser Stelle ist auch, dass es immer eine bessere und einfachere Möglichkeit gibt als Deep zu speichern.

Fazit

Dies sind meine Erfahrungen aus der SAPUI5 Entwicklung mit JSON Models. Die Beispiele, die ich hier beschreibe, sowohl die negativen als auch die positiven, habe ich alle schon erlebt, sei es, dass ich sie selbst so implementiert habe oder die Wartung einer entsprechenden Anwendung übernommen habe.

Gerne kannst du auch deine eigenen Erfahrungen mit JSON Models schildern. Siehst du es genauso wie ich oder womöglich doch ganz anders? Nutze einfach unten die Kommentar-Funktion.

Bis dahin erstmal und kiek mol wedder in!

Schon gesehen?
Arbeiten als SAPUI5-Entwickler bei Acando



Über den Autor

Sebastian Kielhorn

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

37 + = 40