Mit den Grundlagen von UI-Annotationen erreichen Sie schnell erste Ergebnisse. Für professionelle Fiori Elements Apps brauchen Sie jedoch fortgeschrittene Techniken: strukturierte Seitenbereiche mit Facets, dynamische Hervorhebungen, kontextabhängige Sichtbarkeit und analytische Visualisierungen.
Facets: Die Seitenstruktur definieren
Facets bestimmen, wie die Object Page strukturiert ist. Sie definieren Bereiche, Tabs und Feldgruppen:
┌─────────────────────────────────────────────────────────────────────────┐│ [HeaderInfo: Buchungsnummer 12345 - Müller, Hans] │├─────────────────────────────────────────────────────────────────────────┤│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ││ │ Allgemein │ │ Positionen │ │ Historie │ ← Facet Tabs ││ └──────────────┘ └──────────────┘ └──────────────┘ │├─────────────────────────────────────────────────────────────────────────┤│ ┌───────────────────────────┐ ┌───────────────────────────┐ ││ │ Flugdaten │ │ Passagier │ ││ │ ───────────────────── │ │ ───────────────────── │ ││ │ Datum: 15.03.2026 │ │ Name: Hans Müller │ ││ │ Abflug: Frankfurt │ │ Email: [email protected] │ ││ │ Ankunft: New York │ │ Telefon: +49 123 456 │ ││ └───────────────────────────┘ └───────────────────────────┘ ││ ↑ FieldGroups │└─────────────────────────────────────────────────────────────────────────┘Facet-Hierarchie aufbauen
define view entity ZC_FlightBooking as projection on ZI_FlightBooking{ @UI.facet: [ -- Hauptbereich: Collection als Container { id: 'GeneralSection', purpose: #STANDARD, type: #COLLECTION, label: 'Allgemeine Informationen', position: 10 }, -- FieldGroup innerhalb der Collection { id: 'FlightData', parentId: 'GeneralSection', type: #FIELDGROUP_REFERENCE, targetQualifier: 'FlightData', label: 'Flugdaten', position: 10 }, { id: 'PassengerData', parentId: 'GeneralSection', type: #FIELDGROUP_REFERENCE, targetQualifier: 'Passenger', label: 'Passagier', position: 20 }, -- Eigener Tab für Unterpositionen { id: 'ItemsSection', purpose: #STANDARD, type: #LINEITEM_REFERENCE, label: 'Positionen', position: 20, targetElement: '_BookingItems' }, -- Tab für Änderungshistorie { id: 'HistorySection', purpose: #STANDARD, type: #FIELDGROUP_REFERENCE, targetQualifier: 'AdminData', label: 'Historie', position: 30 } ] key BookingId, ...}FieldGroups definieren
Die FieldGroups werden bei den einzelnen Feldern referenziert:
@UI.fieldGroup: [{ qualifier: 'FlightData', position: 10 }] FlightDate,
@UI.fieldGroup: [{ qualifier: 'FlightData', position: 20 }] DepartureAirport,
@UI.fieldGroup: [{ qualifier: 'FlightData', position: 30 }] ArrivalAirport,
@UI.fieldGroup: [{ qualifier: 'Passenger', position: 10 }] PassengerName,
@UI.fieldGroup: [{ qualifier: 'Passenger', position: 20 }] @Semantics.eMail.address: true Email,
@UI.fieldGroup: [{ qualifier: 'Passenger', position: 30 }] @Semantics.telephone.type: [#WORK] Phone,
@UI.fieldGroup: [{ qualifier: 'AdminData', position: 10 }] CreatedBy,
@UI.fieldGroup: [{ qualifier: 'AdminData', position: 20 }] CreatedAt,
@UI.fieldGroup: [{ qualifier: 'AdminData', position: 30 }] LastChangedBy,
@UI.fieldGroup: [{ qualifier: 'AdminData', position: 40 }] LastChangedAtFacet-Typen im Überblick
| Typ | Verwendung |
|---|---|
#COLLECTION | Container für mehrere FieldGroups |
#FIELDGROUP_REFERENCE | Referenziert FieldGroup-Felder |
#LINEITEM_REFERENCE | Tabelle mit Unterpositionen |
#IDENTIFICATION_REFERENCE | Automatisch aus @UI.identification |
#DATAPOINT_REFERENCE | Einzelner DataPoint (z.B. KPI) |
#CHART_REFERENCE | Eingebettetes Diagramm |
HeaderInfo: Der Seitenkopf
HeaderInfo definiert, was im Header der Object Page angezeigt wird:
@UI.headerInfo: { typeName: 'Flugbuchung', typeNamePlural: 'Flugbuchungen', title: { type: #STANDARD, value: 'BookingId', label: 'Buchungsnummer' }, description: { type: #STANDARD, value: 'PassengerName', label: 'Passagier' }, imageUrl: 'AirlineLogoUrl', typeImageUrl: 'sap-icon://flight'}define view entity ZC_FlightBookingWichtige HeaderInfo-Eigenschaften:
| Eigenschaft | Beschreibung |
|---|---|
typeName | Singular-Bezeichnung der Entität |
typeNamePlural | Plural-Bezeichnung für Listen |
title | Haupttitel im Header |
description | Untertitel im Header |
imageUrl | Dynamisches Bild (Feld mit URL) |
typeImageUrl | Statisches Icon |
DataFieldForAction: Aktionsbuttons
Aktionen können in Listen und auf der Object Page platziert werden:
@UI: { lineItem: [ -- Spalteninhalt { position: 10, importance: #HIGH }, -- Aktion in der Listenkopfzeile { position: 100, type: #FOR_ACTION, dataAction: 'confirmBooking', label: 'Bestätigen' }, { position: 110, type: #FOR_ACTION, dataAction: 'cancelBooking', label: 'Stornieren' } ], identification: [ { position: 10 }, -- Aktion auf der Object Page { position: 100, type: #FOR_ACTION, dataAction: 'confirmBooking', label: 'Buchung bestätigen' } ]}key BookingId,Aktionen mit Criticality
Aktionen können farblich hervorgehoben werden:
@UI.lineItem: [{ position: 110, type: #FOR_ACTION, dataAction: 'cancelBooking', label: 'Stornieren', criticality: #NEGATIVE -- Rot}]| Criticality | Farbe | Verwendung |
|---|---|---|
#POSITIVE | Grün | Bestätigen, Freigeben |
#NEGATIVE | Rot | Löschen, Stornieren |
#CRITICAL | Orange | Warnung, Pause |
DataFieldForIntentBasedNavigation
Navigation zu anderen Fiori Apps per Intent:
@UI.lineItem: [{ position: 50, type: #FOR_INTENT_BASED_NAVIGATION, semanticObject: 'Customer', action: 'display', label: 'Kunde anzeigen'}]CustomerId,
-- Mit Parametern@UI.lineItem: [{ position: 60, type: #FOR_INTENT_BASED_NAVIGATION, semanticObject: 'Flight', action: 'manage', label: 'Flug verwalten', mapping: [{ localElement: 'FlightId', semanticObjectAttribute: 'FlightId' }]}]FlightId,Voraussetzung: Die Ziel-App muss im SAP Fiori Launchpad mit entsprechendem Semantic Object und Action konfiguriert sein.
Criticality und Highlighting
Criticality ermöglicht dynamische Farbcodierung basierend auf Datenwerten:
Berechnetes Criticality-Feld
define view entity ZI_FlightBooking{ BookingStatus,
-- Criticality als berechnetes Feld case BookingStatus when 'N' then 2 -- Neu: Gelb when 'C' then 3 -- Bestätigt: Grün when 'X' then 1 -- Storniert: Rot else 0 -- Neutral: Grau end as StatusCriticality,
FlightPrice,
-- Criticality für Preis case when FlightPrice > 2000 then 1 -- Rot: Teuer when FlightPrice > 1000 then 2 -- Gelb: Mittel else 3 -- Grün: Günstig end as PriceCriticality,}Criticality in UI-Annotationen verwenden
@UI.lineItem: [{ position: 30, importance: #HIGH, criticality: 'StatusCriticality', criticalityRepresentation: #WITH_ICON}]BookingStatus,
@UI.lineItem: [{ position: 40, criticality: 'PriceCriticality'}]@Semantics.amount.currencyCode: 'Currency'FlightPrice,
@UI.hidden: trueStatusCriticality,
@UI.hidden: truePriceCriticality,Criticality-Werte
| Wert | Bedeutung | Farbe | Icon |
|---|---|---|---|
| 0 | Neutral | Grau | - |
| 1 | Negative | Rot | ✖ |
| 2 | Critical | Gelb/Orange | ⚠ |
| 3 | Positive | Grün | ✓ |
| 5 | New Item | Blau | (speziell) |
Conditional Visibility
Felder können basierend auf anderen Feldwerten ein- oder ausgeblendet werden:
Hidden mit dynamischem Wert
-- Feld nur für interne Nutzer sichtbar@UI.hidden: #( IsExternalUser )InternalNotes,
-- Das steuernde Feld (berechneter Boolean)case when UserType = 'EXTERNAL' then abap_true else abap_falseend as IsExternalUser,Conditional Visibility über Annotations
-- Feld nur anzeigen wenn Status = 'C' (bestätigt)@UI.fieldGroup: [{ qualifier: 'ConfirmationData', position: 10, hidden: #( IsNotConfirmed )}]ConfirmationDate,
@UI.fieldGroup: [{ qualifier: 'ConfirmationData', position: 20, hidden: #( IsNotConfirmed )}]ConfirmedBy,
-- Steuerungsfeldcase when BookingStatus <> 'C' then abap_true else abap_false end as IsNotConfirmed,Read-Only basierend auf Status
-- Felder nur bearbeitbar wenn Status = 'N' (neu)@UI.fieldGroup: [{ qualifier: 'FlightData', position: 10}]@ObjectModel.readOnly: #( IsNotEditable )FlightDate,
case when BookingStatus <> 'N' then abap_true else abap_false end as IsNotEditable,Chart Annotationen
Eingebettete Diagramme in der Object Page:
Micro Chart im LineItem
@UI.lineItem: [{ position: 60, type: #AS_CHART, valueQualifier: 'OccupancyChart'}]@UI.chart: [{ qualifier: 'OccupancyChart', chartType: #BULLET, measures: ['OccupancyRate'], measureAttributes: [{ measure: 'OccupancyRate', role: #AXIS_1 }], description: 'Auslastung'}]@UI.dataPoint: { qualifier: 'OccupancyChart', targetValue: 100, criticalityCalculation: { improvementDirection: #MAXIMIZE, toleranceRangeLowValue: 50, deviationRangeLowValue: 25 }}OccupancyRate,Chart in Facet
@UI.facet: [{ id: 'AnalyticsSection', purpose: #STANDARD, type: #CHART_REFERENCE, targetQualifier: 'RevenueChart', label: 'Umsatzentwicklung', position: 40}]
@UI.chart: [{ qualifier: 'RevenueChart', chartType: #COLUMN, dimensions: ['Month'], measures: ['Revenue'], dimensionAttributes: [{ dimension: 'Month', role: #CATEGORY }], measureAttributes: [{ measure: 'Revenue', role: #AXIS_1 }]}]Chart-Typen
| ChartType | Beschreibung |
|---|---|
#COLUMN | Säulendiagramm |
#BAR | Balkendiagramm |
#LINE | Liniendiagramm |
#PIE | Kreisdiagramm |
#DONUT | Ringdiagramm |
#BULLET | Bullet Chart (Micro) |
#COMPARISON | Vergleichschart |
KPI Annotationen
Key Performance Indicators im Header:
@UI.headerInfo: { typeName: 'Flugbuchung', typeNamePlural: 'Flugbuchungen', title: { type: #STANDARD, value: 'BookingId' }}@UI.facet: [{ id: 'KPIHeader', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'TotalRevenue', position: 10}]define view entity ZC_FlightBooking{ @UI.dataPoint: { qualifier: 'TotalRevenue', title: 'Gesamtumsatz', criticalityCalculation: { improvementDirection: #MAXIMIZE, toleranceRangeLowValue: 10000, deviationRangeLowValue: 5000 } } @Semantics.amount.currencyCode: 'Currency' TotalRevenue,}Mehrere KPIs im Header
@UI.facet: [ { id: 'KPI_Revenue', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'Revenue', position: 10 }, { id: 'KPI_Bookings', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'BookingCount', position: 20 }, { id: 'KPI_Occupancy', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'Occupancy', position: 30 }]
@UI.dataPoint: { qualifier: 'Revenue', title: 'Umsatz', visualization: #NUMBER}TotalRevenue,
@UI.dataPoint: { qualifier: 'BookingCount', title: 'Buchungen', visualization: #NUMBER}NumberOfBookings,
@UI.dataPoint: { qualifier: 'Occupancy', title: 'Auslastung', visualization: #PROGRESS, targetValue: 100}OccupancyPercent,Vollständiges Flugbuchung-Beispiel
@EndUserText.label: 'Flugbuchung Projection'@Metadata.allowExtensions: true
@UI.headerInfo: { typeName: 'Flugbuchung', typeNamePlural: 'Flugbuchungen', title: { type: #STANDARD, value: 'BookingId' }, description: { type: #STANDARD, value: 'PassengerName' }, typeImageUrl: 'sap-icon://flight'}
define view entity ZC_FlightBooking as projection on ZI_FlightBooking{ @UI.facet: [ -- Header KPIs { id: 'KPI_Price', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'FlightPrice', position: 10 }, -- Hauptbereich { id: 'GeneralSection', purpose: #STANDARD, type: #COLLECTION, label: 'Buchungsdetails', position: 10 }, { id: 'FlightData', parentId: 'GeneralSection', type: #FIELDGROUP_REFERENCE, targetQualifier: 'Flight', label: 'Flugdaten', position: 10 }, { id: 'PassengerData', parentId: 'GeneralSection', type: #FIELDGROUP_REFERENCE, targetQualifier: 'Passenger', label: 'Passagier', position: 20 }, -- Admin-Bereich { id: 'AdminSection', purpose: #STANDARD, type: #FIELDGROUP_REFERENCE, targetQualifier: 'Admin', label: 'Verwaltung', position: 20 } ]
@UI: { lineItem: [ { position: 10, importance: #HIGH }, { position: 100, type: #FOR_ACTION, dataAction: 'confirmBooking', label: 'Bestätigen' }, { position: 110, type: #FOR_ACTION, dataAction: 'cancelBooking', label: 'Stornieren', criticality: #NEGATIVE } ], identification: [ { position: 10 }, { position: 100, type: #FOR_ACTION, dataAction: 'confirmBooking', label: 'Buchung bestätigen' } ], selectionField: [{ position: 10 }] } key BookingId,
@UI: { lineItem: [{ position: 20, importance: #HIGH, criticality: 'StatusCriticality', criticalityRepresentation: #WITH_ICON }], identification: [{ position: 20 }], selectionField: [{ position: 20 }] } BookingStatus,
@UI.hidden: true StatusCriticality,
@UI: { lineItem: [{ position: 30, importance: #MEDIUM }], fieldGroup: [{ qualifier: 'Flight', position: 10 }] } FlightDate,
@UI.fieldGroup: [{ qualifier: 'Flight', position: 20 }] DepartureAirport,
@UI.fieldGroup: [{ qualifier: 'Flight', position: 30 }] ArrivalAirport,
@UI: { lineItem: [{ position: 40, importance: #HIGH }], dataPoint: { qualifier: 'FlightPrice', title: 'Preis' } } @Semantics.amount.currencyCode: 'Currency' FlightPrice,
@UI.hidden: true Currency,
@UI: { lineItem: [{ position: 50, type: #FOR_INTENT_BASED_NAVIGATION, semanticObject: 'Customer', action: 'display' }], fieldGroup: [{ qualifier: 'Passenger', position: 10 }] } PassengerName,
@UI.fieldGroup: [{ qualifier: 'Passenger', position: 20 }] @Semantics.eMail.address: true Email,
@UI.fieldGroup: [{ qualifier: 'Passenger', position: 30 }] @Semantics.telephone.type: [#WORK] Phone,
@UI.fieldGroup: [{ qualifier: 'Admin', position: 10, label: 'Erstellt von' }] @Semantics.user.createdBy: true CreatedBy,
@UI.fieldGroup: [{ qualifier: 'Admin', position: 20, label: 'Erstellt am' }] @Semantics.systemDateTime.createdAt: true CreatedAt,
@UI.fieldGroup: [{ qualifier: 'Admin', position: 30, label: 'Geändert von' }] @Semantics.user.lastChangedBy: true LastChangedBy,
@UI.fieldGroup: [{ qualifier: 'Admin', position: 40, label: 'Geändert am' }] @Semantics.systemDateTime.lastChangedAt: true LastChangedAt}Best Practices
| Aspekt | Empfehlung |
|---|---|
| Facet-Struktur | Collections für zusammengehörige FieldGroups nutzen |
| Criticality | Sparsam einsetzen, nur bei echter Bedeutung (Status, Grenzwerte) |
| Hidden Fields | Berechnete Steuerungsfelder immer mit @UI.hidden: true |
| HeaderInfo | Aussagekräftigen Titel und Beschreibung wählen |
| Actions | Wichtige Aktionen in lineItem, alle in identification |
| KPIs | Max. 3-4 KPIs im Header für Übersichtlichkeit |
| Charts | Micro Charts für Trends, vollständige Charts in eigenen Facets |
| Navigation | Intent-Based Navigation für konsistente App-zu-App-Navigation |
Zusammenfassung
Fortgeschrittene UI-Annotationen ermöglichen professionelle Fiori Elements Apps ohne Frontend-Code. Mit Facets strukturieren Sie Seiten logisch, Criticality macht Status visuell erkennbar, und Charts/KPIs liefern Analysefähigkeiten direkt in der Anwendung.
Weiterführende Artikel: CDS Annotations Grundlagen für die Basics, RAP Actions und Functions für Aktionsimplementierung, RAP Nachrichten in Fiori für Benutzer-Feedback und Fiori Elements UI ohne Code für den Einstieg.