
RAP - UI Annotationen
Heute schauen wir uns einmal an, wie wir die Fiori Elements mit Standardelementen anreichern können, um so direkt eine fertige App zu erhalten.
Inhaltsverzeichnis
Über UI Annotationen werden wir in einem eigenen großen Artikel noch einmal über die vielfältigen Elemente und Möglichkeiten schreiben. In diesem ersten Teil wollen wir vor allem das Beispiel von letzter Woche mit Standardelementen anreichern, sodass beim Laden der Applikation gleich die fertige App zu sehen ist.
Annotation
Über Annotationen in CDS Views hatten wir bereits im Blog für die Core Data Services Grundlagen geschrieben. Mit diesen Zusatzeigenschaften kannst du Felder mit weiteren Funktionen und Verhalten ausstatten. Ebenso wollen wir zusätzliches Verhalten und eine UI für unseren Core Data Service erhalten. Dazu können wir die Felder mit Annotationen der Familie UI ausstatten.
Selektion
Soll über gewisse Felder von vornherein gefiltert werden, können wir das direkt über die Annotation "UI.selectionField" definieren. Dabei werden die Felder als Suchfelder angezeigt, können im Nachgang aber noch über die Standardfunktionalität erweitert oder ausgeblendet werden.
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
@UI.selectionField : [ { position: 10 } ]
key partner as PartnerNumber,
@UI.selectionField : [ { position: 20 } ]
name as PartnerName,
street as Street,
city as City,
country as Country,
payment_currency as PaymentCurrency
}
Die Nummer der Position ist frei wählbar, darf aber nur einmal innerhalb des Views vergeben werden. Sie bestimmt die Reihenfolge, in der die Element angezeigt werden, deshalb werden die Elemente zu Anfang in 10er Schritten nummeriert, damit Elemente noch dazwischen eingefügt werden können. Das Ergebnis sieht nun wie folgt aus:
Liste
Als nächstes möchten wir gern gewisse Elemente in der Liste darstellen, die nach dem Laden ausgegeben werden. Dies erreichen wir mit der Annotation "UI.lineItem" die so ähnlich die Selektion arbeitet. Wir können eine bestimmte Reihenfolge angeben, in der die Elemente in der Liste eingefügt werden. Mit dem Attribut "importance" können wir allerdings auch festlegen, welche Informationen angezeigt werden, wenn nicht alle Elemente auf den Bildschirm passen.
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
@UI.selectionField : [ { position: 10 } ]
@UI.lineItem: [{ position: 20, importance: #MEDIUM }]
key partner as PartnerNumber,
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
name as PartnerName,
@UI.lineItem: [{ position: 40, importance: #MEDIUM }]
street as Street,
@UI.lineItem: [{ position: 30, importance: #MEDIUM }]
city as City,
@UI.lineItem: [{ position: 50, importance: #HIGH }]
country as Country,
payment_currency as PaymentCurrency
}
Die Spalte Land ist bei der Liste sichtbar, da das Element mit einer sehr hohen Priorität angezeigt wird. Haben alle Elemente die gleiche Priorität, dann werden sie der Reihe nach aufgebaut, bis kein Platz mehr verfügbar ist.
Texte
Bisher fehlen den Spalten noch ordentliche Überschriften. Dies kannst du erreichen, wenn du ordentliche Datenelemente verwendest, aus denen die Texte abgeleitet werden können. In unserem Fall gibt es nur eingebaute Datentypen, wir möchten allerdings im UI ordentliche Texte darstellen. Dazu kann der Text mit "EndUserText" angepasst werden, dazu gibt es die Elemente "label" für den Text der Spalte und "quickinfo", dieser Text wird angezeigt, wenn man mit der Maus über die Überschrift geht.
Damit sieht die Liste schon viel aufgeräumter aus und bietet dem Anwender Erläuterungen bei der Interpretation der Ausgabeliste.
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
@UI.selectionField : [ { position: 10 } ]
@UI.lineItem: [{ position: 20, importance: #MEDIUM }]
@EndUserText.label: 'Partner'
@EndUserText.quickInfo: 'Identifier of the partner'
key partner as PartnerNumber,
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
@EndUserText.label: 'Name'
@EndUserText.quickInfo: 'Partner name'
name as PartnerName,
@UI.lineItem: [{ position: 40, importance: #MEDIUM }]
@EndUserText.label: 'Street'
@EndUserText.quickInfo: 'Street and Housenumber'
street as Street,
@UI.lineItem: [{ position: 30, importance: #MEDIUM }]
@EndUserText.label: 'City'
@EndUserText.quickInfo: 'City of the partner'
city as City,
@UI.lineItem: [{ position: 50, importance: #HIGH }]
@EndUserText.label: 'Ctry'
@EndUserText.quickInfo: 'Country'
country as Country,
@EndUserText.label: 'PayCurr'
@EndUserText.quickInfo: 'Payment currency'
payment_currency as PaymentCurrency
}
Detailbild
Wenn du aktuell auf einen Datensatz in der Liste klickst, kommst du automatisch in das Detailbild der Anwendung, doch dieses ist noch leer. Aktuell haben wir für dieses Bild noch keine Informationen hinterlegt. Wie bereits oben hinterlegen wir am Feld eine neue Annotation "UI.identification". Damit ist allerdings immer noch nichts auf dem Detailbild zu sehen, sondern wir müssen die Felder einer Art von Gruppe zuordnen.
Dazu definieren wir am Anfang des Views eine Facet. Dieses Objekt unterteilt das Bild in verschiedene Bereiche und so können wir Elemente bzw. Felder zuordnen. Facets haben eine ID und müssen eindeutig auf dem Bild sein, ist dies nicht der Fall, werden keine Elemente auf dem Bild angezeigt.
Eine Gruppe
Bei der Gestaltung des Bildes haben wir nun freie Auswahl, wie das Bild gestaltet werden soll. Beginnen wir dazu mit einer einfachen Variante und packen alles unter eine Kategorie.
@UI.facet : [
{
id : 'FacetPartnerFields',
label : 'Partner Informations',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
}
]
Innerhalb des Facets definieren wir einen Bereich vom Typ "IDENTIFICATION_REFERENCE" worunter alle Objekte fallen, wir setzen eine entsprechende ID und ein Label der angezeigt werden soll. Der "targetQualifier" dient dazu, dem Element die entsprechenden Felder zuordnen zu können. Dies geschieht über die entsprechende Annotation:
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
@UI.identification: [{ position: 20, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Name'
@EndUserText.quickInfo: 'Partner name'
name as PartnerName,
Am Ende sieht das Detailbild wie folgt aus:
Zwei Reiter
Die nächste Variante erzeugt zwei "Reiter" auf dem Bild. Über die Reiter kann später auch auf dem Detailbild navigiert werden, wenn viele Felder vorhanden sind, um so zu dem passenden Abschnitt zu gelangen. Dabei ergänzen wir das Facet um einen zweiten Eintrag mit neuer ID und neuer Zuordnung für die Felder:
@UI.facet : [
{
id : 'FacetPartnerFields',
label : 'Information',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
},
{
id : 'FacetPartnerAddress',
label : 'Address',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_ADDRESS'
}
]
Die Felder können nun, wie im letzten Abschnitt, dem entsprechenden Facet zugeordnet werden und erhalten nun folgendes Detailbild (die Reiter oben sind gut zu erkennen):
Collection
Die dritte und finale Form des Bildes ist die "Collection" eine Zusammenfassung von verschiedenen Referenzen unter einer Kategorie. Dazu definieren wir ein weiteres Facet mit dem entsprechenden Typen und vergeben auch ein Label, da dies als neuer Reiter angezeigt wird. Die anderen beiden Facets erhalten nun eine "parentId", damit wird die Zuordnung zur Collection sichergestellt.
@UI.facet : [
{
id : 'FacetCollection',
type : #COLLECTION,
label : 'Partner Collection'
},
{
id : 'FacetPartnerFields',
parentId : 'FacetCollection',
label : 'Information',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
},
{
id : 'FacetPartnerAddress',
parentId : 'FacetCollection',
label : 'Address',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_ADDRESS'
}
]
Die entsprechenden Felder können wieder zugeordnet werden und du erhältst das finale Bild. Die Beiden Facets werden in einem Bereich zusammengefasst und erhalten eine Überschrift, die Objekt sind in Bereiche gruppiert.
Hier noch einmal der gesamte Core Data Service mit allen Annotationen für das letzte Beispiel. Wie du siehst, hat sich die Menge des Codings stark erhöht.
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'RAP interface for Partner'
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
@UI.facet : [
{
id : 'FacetCollection',
type : #COLLECTION,
label : 'Partner Collection'
},
{
id : 'FacetPartnerFields',
parentId : 'FacetCollection',
label : 'Information',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
},
{
id : 'FacetPartnerAddress',
parentId : 'FacetCollection',
label : 'Address',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_ADDRESS'
}
]
@UI.selectionField : [ { position: 10 } ]
@UI.lineItem: [{ position: 20, importance: #MEDIUM }]
@UI.identification: [{ position: 10, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Partner'
@EndUserText.quickInfo: 'Identifier of the partner'
key partner as PartnerNumber,
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
@UI.identification: [{ position: 20, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Name'
@EndUserText.quickInfo: 'Partner name'
name as PartnerName,
@UI.lineItem: [{ position: 40, importance: #MEDIUM }]
@UI.identification: [{ position: 30, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'Street'
@EndUserText.quickInfo: 'Street and Housenumber'
street as Street,
@UI.lineItem: [{ position: 30, importance: #MEDIUM }]
@UI.identification: [{ position: 40, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'City'
@EndUserText.quickInfo: 'City of the partner'
city as City,
@UI.lineItem: [{ position: 50, importance: #HIGH }]
@UI.identification: [{ position: 50, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'Ctry'
@EndUserText.quickInfo: 'Country'
country as Country,
@UI.identification: [{ position: 60, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'PayCurr'
@EndUserText.quickInfo: 'Payment currency'
payment_currency as PaymentCurrency
}
Metadata
Die UI Annotaionen können mit der Zeit stark anwachsen und im eigentlichen View für Unübersichtlichkeit sorgen. Dafür können wir eine Metadata Extension anlegen, um alle nötigen UI Annotationen in ein separates Objekt zu transferieren. Dafür musst du im zu erweiternden View eine Annotation anlegen:
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'RAP interface for Partner'
@Metadata.allowExtensions: true
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
key partner as PartnerNumber,
name as PartnerName,
street as Street,
city as City,
country as Country,
payment_currency as PaymentCurrency
}
Mit "@Metadata.allowExtensions" wird bekannt gegeben, dass der View mit Extensions erweitert werden kann. Im Anschluss kannst du mit Recht-Klick auf den CDS View im Project Explorer die "Metadata Extension" anlegen und die Annotationen in die neue Datei verschieben.
Nach dem Verschieben sieht die Extionsion wie folgt aus, dabei solltest du allerdings beachten, dass sich im Gegensatz zum Interface View nun einiges geändert hat. Die Felder werden nun mit einem Semikolon abgeschlossen und es wird nur der Feldname benötigt (ohne Schlüsselwörter wie "key").
@Metadata.layer: #CUSTOMER
annotate view ZBS_I_RAPPartner with
{
@UI.facet : [
{
id : 'FacetCollection',
type : #COLLECTION,
label : 'Partner Collection'
},
{
id : 'FacetPartnerFields',
parentId : 'FacetCollection',
label : 'Information',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
},
{
id : 'FacetPartnerAddress',
parentId : 'FacetCollection',
label : 'Address',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_ADDRESS'
}
]
@UI.selectionField : [ { position: 10 } ]
@UI.lineItem: [{ position: 20, importance: #MEDIUM }]
@UI.identification: [{ position: 10, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Partner'
@EndUserText.quickInfo: 'Identifier of the partner'
PartnerNumber;
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
@UI.identification: [{ position: 20, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Name'
@EndUserText.quickInfo: 'Partner name'
PartnerName;
@UI.lineItem: [{ position: 40, importance: #MEDIUM }]
@UI.identification: [{ position: 30, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'Street'
@EndUserText.quickInfo: 'Street and Housenumber'
Street;
@UI.lineItem: [{ position: 30, importance: #MEDIUM }]
@UI.identification: [{ position: 40, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'City'
@EndUserText.quickInfo: 'City of the partner'
City;
@UI.lineItem: [{ position: 50, importance: #HIGH }]
@UI.identification: [{ position: 50, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'Ctry'
@EndUserText.quickInfo: 'Country'
Country;
@UI.identification: [{ position: 60, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'PayCurr'
@EndUserText.quickInfo: 'Payment currency'
PaymentCurrency;
}
Fazit
In diesem Artikel haben wir unsere Fiori Elements mit Feldern und Abschnitten angereichert und so eine echte Anwendung erstellt, mit der man sofort arbeiten kann. Dabei sind wir auf die verschiedenen Möglichkeiten zur Gestaltung eingegangen und wie du das Detailbild effektiver hinbekommst. Den aktuellen Quellcode findest du wieder über GitHub.