Die Object Page zeigt Detail-Informationen zu einem einzelnen Business-Objekt. Sie ist das Herzstück transaktionaler Fiori-Anwendungen und ermöglicht das Anzeigen, Bearbeiten und Verwalten von Daten. Über CDS-Annotations lässt sich das Layout präzise steuern – von Header-Informationen über strukturierte Sections bis hin zu eingebetteten Tabellen.
Object Page Struktur
Eine Object Page besteht aus klar definierten Bereichen:
┌─────────────────────────────────────────────────────────────┐│ Object Page Header ││ ┌───────────────────────┬──────────────────────────────┐ ││ │ Object Image/ │ Header Facets │ ││ │ Avatar │ (KPIs, Status, Ratings) │ ││ ├───────────────────────┴──────────────────────────────┤ ││ │ Title: Bestellung 4711 │ ││ │ Subtitle: Kunde: Mustermann GmbH │ ││ └──────────────────────────────────────────────────────┘ │├─────────────────────────────────────────────────────────────┤│ [Tab 1: Allgemein] [Tab 2: Positionen] [Tab 3: Historie] │├─────────────────────────────────────────────────────────────┤│ Section Content ││ ┌─────────────────────────────────────────────────────┐ ││ │ Subsection: Basisdaten │ ││ │ ┌─────────────────┬─────────────────┐ │ ││ │ │ Field Group 1 │ Field Group 2 │ │ ││ │ │ - Feld A │ - Feld D │ │ ││ │ │ - Feld B │ - Feld E │ │ ││ │ │ - Feld C │ - Feld F │ │ ││ │ └─────────────────┴─────────────────┘ │ ││ └─────────────────────────────────────────────────────┘ ││ ┌─────────────────────────────────────────────────────┐ ││ │ Subsection: Positionen (Table) │ ││ │ | Pos | Material | Menge | Preis | │ ││ │ |-----|----------|-------|-------| │ ││ │ | 10 | MAT-001 | 5 | 100€ | │ ││ └─────────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────────┘Grundlegende Object Page Konfiguration
Header Title und Subtitle
@UI.headerInfo: { typeName: 'Bestellung', typeNamePlural: 'Bestellungen', title: { type: #STANDARD, value: 'OrderId' }, description: { type: #STANDARD, value: 'CustomerName' }, imageUrl: 'ImageUrl' -- Optional: Bild/Avatar}define view entity ZC_SalesOrder as projection on ZI_SalesOrder{ ...}Object Page mit Facets definieren
@UI.facet: [ -- Header Facets { id: 'HeaderStatus', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'Status', position: 10 }, { id: 'HeaderTotal', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'TotalAmount', position: 20 },
-- Content Sections { id: 'GeneralSection', purpose: #STANDARD, type: #COLLECTION, label: 'Allgemein', position: 10 }, { id: 'ItemsSection', purpose: #STANDARD, type: #LINEITEM_REFERENCE, label: 'Positionen', position: 20, targetElement: '_Items' }]Multiple Sections mit Tabs
Mehrere Sections werden automatisch als Tabs dargestellt, wenn sie auf der gleichen Ebene definiert sind.
Beispiel: Drei-Tab-Layout
@UI.facet: [ -- Tab 1: Allgemein { id: 'GeneralTab', purpose: #STANDARD, type: #COLLECTION, label: 'Allgemein', position: 10 }, { id: 'GeneralBasic', parentId: 'GeneralTab', type: #FIELDGROUP_REFERENCE, targetQualifier: 'BasicData', label: 'Basisdaten', position: 10 }, { id: 'GeneralDates', parentId: 'GeneralTab', type: #FIELDGROUP_REFERENCE, targetQualifier: 'Dates', label: 'Termine', position: 20 },
-- Tab 2: Positionen { id: 'ItemsTab', purpose: #STANDARD, type: #COLLECTION, label: 'Positionen', position: 20 }, { id: 'ItemsTable', parentId: 'ItemsTab', type: #LINEITEM_REFERENCE, label: 'Bestellpositionen', targetElement: '_Items', position: 10 },
-- Tab 3: Historie { id: 'HistoryTab', purpose: #STANDARD, type: #COLLECTION, label: 'Historie', position: 30 }, { id: 'ChangeLog', parentId: 'HistoryTab', type: #LINEITEM_REFERENCE, label: 'Aenderungsprotokoll', targetElement: '_ChangeLog', position: 10 }]Subsections innerhalb von Tabs
Für komplexere Layouts können Tabs weitere Unterteilungen haben:
@UI.facet: [ { id: 'GeneralTab', purpose: #STANDARD, type: #COLLECTION, label: 'Allgemein', position: 10 }, -- Subsection 1: Kopfdaten { id: 'HeaderData', parentId: 'GeneralTab', type: #COLLECTION, label: 'Kopfdaten', position: 10 }, { id: 'HeaderFields', parentId: 'HeaderData', type: #FIELDGROUP_REFERENCE, targetQualifier: 'HeaderFields', position: 10 }, -- Subsection 2: Konditionen { id: 'Conditions', parentId: 'GeneralTab', type: #COLLECTION, label: 'Konditionen', position: 20 }, { id: 'ConditionFields', parentId: 'Conditions', type: #FIELDGROUP_REFERENCE, targetQualifier: 'ConditionFields', position: 10 }]Field Groups und Form Layouts
Field Groups organisieren Felder in logischen Blöcken. Sie werden als Formularbereiche dargestellt.
Field Group Definition
define view entity ZC_SalesOrder as projection on ZI_SalesOrder{ @UI.facet: [ { id: 'BasicDataSection', type: #COLLECTION, label: 'Basisdaten', position: 10 }, { id: 'OrderInfo', parentId: 'BasicDataSection', type: #FIELDGROUP_REFERENCE, targetQualifier: 'OrderInfo', label: 'Bestellinformationen', position: 10 }, { id: 'CustomerInfo', parentId: 'BasicDataSection', type: #FIELDGROUP_REFERENCE, targetQualifier: 'CustomerInfo', label: 'Kundeninformationen', position: 20 } ]
@UI.fieldGroup: [{ qualifier: 'OrderInfo', position: 10 }] @UI.identification: [{ position: 10 }] key OrderId,
@UI.fieldGroup: [{ qualifier: 'OrderInfo', position: 20 }] OrderDate,
@UI.fieldGroup: [{ qualifier: 'OrderInfo', position: 30 }] Status,
@UI.fieldGroup: [{ qualifier: 'CustomerInfo', position: 10 }] CustomerId,
@UI.fieldGroup: [{ qualifier: 'CustomerInfo', position: 20 }] CustomerName,
@UI.fieldGroup: [{ qualifier: 'CustomerInfo', position: 30 }] CustomerCity}Mehrspaltiges Layout
Field Groups werden standardmäßig nebeneinander dargestellt. Für explizite Kontrolle:
@UI.facet: [ { id: 'TwoColumnSection', type: #COLLECTION, label: 'Zwei Spalten', position: 10 }, { id: 'LeftColumn', parentId: 'TwoColumnSection', type: #FIELDGROUP_REFERENCE, targetQualifier: 'LeftFields', label: 'Linke Spalte', position: 10 }, { id: 'RightColumn', parentId: 'TwoColumnSection', type: #FIELDGROUP_REFERENCE, targetQualifier: 'RightFields', label: 'Rechte Spalte', position: 20 }]Inline Tables in Object Page
Untergeordnete Entitäten können als Tabellen direkt in der Object Page angezeigt werden.
Standard LineItem Table
-- In der Root Entity@UI.facet: [{ id: 'ItemsSection', purpose: #STANDARD, type: #LINEITEM_REFERENCE, label: 'Positionen', targetElement: '_Items', position: 20}]
-- In der untergeordneten Entity (Items)define view entity ZC_SalesOrderItem as projection on ZI_SalesOrderItem{ @UI.lineItem: [{ position: 10 }] key OrderId,
@UI.lineItem: [{ position: 20 }] key ItemNumber,
@UI.lineItem: [{ position: 30 }] MaterialNumber,
@UI.lineItem: [{ position: 40 }] Quantity,
@UI.lineItem: [{ position: 50 }] @Semantics.amount.currencyCode: 'Currency' NetPrice,
@UI.lineItem: [{ position: 60 }] Currency}Table mit Actions
define view entity ZC_SalesOrderItem as projection on ZI_SalesOrderItem{ @UI.lineItem: [ { position: 10 }, { type: #FOR_ACTION, dataAction: 'deleteItem', label: 'Loeschen' }, { type: #FOR_ACTION, dataAction: 'copyItem', label: 'Kopieren' } ] key ItemNumber, ...}Editierbare Inline-Tabelle
Für editierbare Tabellen muss die Behavior Definition entsprechend konfiguriert sein:
define behavior for ZI_SalesOrder alias SalesOrder{ ... association _Items { create; }}
define behavior for ZI_SalesOrderItem alias SalesOrderItem{ update; delete; field ( readonly ) OrderId, ItemNumber; field ( mandatory ) MaterialNumber, Quantity;}Custom Actions auf Object Page
Actions können im Header, in Sections oder auf Feldebene platziert werden.
Header Actions
@UI.identification: [ { position: 10 }, { type: #FOR_ACTION, dataAction: 'approve', label: 'Genehmigen' }, { type: #FOR_ACTION, dataAction: 'reject', label: 'Ablehnen' }, { type: #FOR_ACTION, dataAction: 'sendEmail', label: 'E-Mail senden' }]key OrderId,Actions mit Criticality (Farbcodierung)
@UI.identification: [{ type: #FOR_ACTION, dataAction: 'approve', label: 'Genehmigen', criticality: 'ApproveCriticality' -- Dynamische Kritikalitaet}]key OrderId,
-- Berechnetes Feld fuer Criticality@UI.hidden: truecast( case Status when 'OPEN' then 3 -- Gruen when 'PENDING' then 2 -- Gelb else 0end as abap.int1 ) as ApproveCriticality,Conditional Actions (Feature Control)
Actions können basierend auf Daten ein-/ausgeblendet werden:
-- In der Behavior Definitiondefine behavior for ZI_SalesOrder alias SalesOrder{ action approve result [1] $self;
// Feature Control determination setFeatures on modify { field Status; }}-- In der Behavior ImplementationMETHOD get_instance_features. READ ENTITIES OF zi_salesorder IN LOCAL MODE ENTITY SalesOrder FIELDS ( Status ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_orders).
LOOP AT lt_orders INTO DATA(ls_order). APPEND VALUE #( %tky = ls_order-%tky %action-approve = COND #( WHEN ls_order-Status = 'OPEN' THEN if_abap_behv=>fc-o-enabled ELSE if_abap_behv=>fc-o-disabled ) ) TO result. ENDLOOP.ENDMETHOD.Actions in Sections
@UI.facet: [{ id: 'AdminSection', purpose: #STANDARD, type: #COLLECTION, label: 'Administration', position: 40}]
-- Feldgruppe mit Actions@UI.fieldGroup: [{ qualifier: 'AdminActions', position: 10, type: #FOR_ACTION, dataAction: 'archive', label: 'Archivieren'}]Responsive Layout-Anpassungen
Fiori Elements passt das Layout automatisch an verschiedene Bildschirmgrößen an. Zusätzliche Kontrolle ist möglich.
Importance für responsive Anpassung
@UI.lineItem: [{ position: 10, importance: #HIGH -- Immer sichtbar}]OrderId,
@UI.lineItem: [{ position: 20, importance: #MEDIUM -- Ausgeblendet auf kleinen Screens}]OrderDate,
@UI.lineItem: [{ position: 30, importance: #LOW -- Nur auf grossen Screens}]CreatedBy,Hidden Fields
Felder können komplett ausgeblendet werden:
@UI.hidden: trueInternalField,
-- Oder dynamisch@UI.hidden: #( HideCondition )ConditionalField,FieldGroup Column Layout
@UI.fieldGroup: [{ qualifier: 'Details', position: 10, label: 'Bestellnummer'}]@EndUserText.label: 'Bestellnummer'OrderId,Header Facets konfigurieren
DataPoint im Header
@UI.facet: [{ id: 'HeaderStatus', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'StatusDP', position: 10}]
@UI.dataPoint: { qualifier: 'StatusDP', title: 'Status', criticality: 'StatusCriticality'}Status,Progress Indicator
@UI.dataPoint: { qualifier: 'Completion', title: 'Fertigstellung', visualization: #PROGRESS, targetValue: 100}CompletionPercent,Rating Indicator
@UI.dataPoint: { qualifier: 'CustomerRating', title: 'Kundenbewertung', visualization: #RATING, targetValue: 5}Rating,Contact Card im Header
@UI.facet: [{ id: 'ContactCard', purpose: #HEADER, type: #CONTACT_REFERENCE, targetElement: '_Contact', position: 30}]Vollständiges Beispiel
@EndUserText.label: 'Sales Order - Projection'@Metadata.allowExtensions: true@UI.headerInfo: { typeName: 'Bestellung', typeNamePlural: 'Bestellungen', title: { type: #STANDARD, value: 'OrderId' }, description: { type: #STANDARD, value: 'CustomerName' }}define view entity ZC_SalesOrder as projection on ZI_SalesOrder{ @UI.facet: [ -- Header Facets { id: 'HeaderStatus', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'Status', position: 10 }, { id: 'HeaderTotal', purpose: #HEADER, type: #DATAPOINT_REFERENCE, targetQualifier: 'TotalAmount', position: 20 },
-- Tab 1: Allgemein { id: 'GeneralTab', purpose: #STANDARD, type: #COLLECTION, label: 'Allgemein', position: 10 }, { id: 'OrderData', parentId: 'GeneralTab', type: #FIELDGROUP_REFERENCE, targetQualifier: 'OrderData', label: 'Bestelldaten', position: 10 }, { id: 'CustomerData', parentId: 'GeneralTab', type: #FIELDGROUP_REFERENCE, targetQualifier: 'CustomerData', label: 'Kundendaten', position: 20 },
-- Tab 2: Positionen { id: 'ItemsTab', purpose: #STANDARD, type: #COLLECTION, label: 'Positionen', position: 20 }, { id: 'ItemsTable', parentId: 'ItemsTab', type: #LINEITEM_REFERENCE, targetElement: '_Items', label: 'Bestellpositionen', position: 10 },
-- Tab 3: Notizen { id: 'NotesTab', purpose: #STANDARD, type: #COLLECTION, label: 'Notizen', position: 30 }, { id: 'NotesField', parentId: 'NotesTab', type: #FIELDGROUP_REFERENCE, targetQualifier: 'Notes', position: 10 } ]
@UI.identification: [ { position: 10 }, { type: #FOR_ACTION, dataAction: 'approve', label: 'Genehmigen' }, { type: #FOR_ACTION, dataAction: 'reject', label: 'Ablehnen' } ] @UI.fieldGroup: [{ qualifier: 'OrderData', position: 10 }] key OrderId,
@UI.dataPoint: { qualifier: 'Status', title: 'Status', criticality: 'StatusCriticality' } @UI.fieldGroup: [{ qualifier: 'OrderData', position: 20 }] Status,
@UI.hidden: true StatusCriticality,
@UI.fieldGroup: [{ qualifier: 'OrderData', position: 30 }] OrderDate,
@UI.dataPoint: { qualifier: 'TotalAmount', title: 'Gesamtbetrag' } @UI.fieldGroup: [{ qualifier: 'OrderData', position: 40 }] @Semantics.amount.currencyCode: 'Currency' TotalAmount,
Currency,
@UI.fieldGroup: [{ qualifier: 'CustomerData', position: 10 }] CustomerId,
@UI.fieldGroup: [{ qualifier: 'CustomerData', position: 20 }] CustomerName,
@UI.fieldGroup: [{ qualifier: 'CustomerData', position: 30 }] CustomerCity,
@UI.fieldGroup: [{ qualifier: 'Notes', position: 10 }] @UI.multiLineText: true Notes,
-- Assoziationen _Items : redirected to composition child ZC_SalesOrderItem}Best Practices
| Aspekt | Empfehlung |
|---|---|
| Tab-Anzahl | Maximal 5-7 Tabs fuer Uebersichtlichkeit |
| Field Groups | Logische Gruppierung, max. 6-8 Felder pro Gruppe |
| Header Facets | Nur wichtigste KPIs, max. 4-5 Facets |
| Actions | Primaere Aktionen prominent, sekundaere in Menue |
| Inline Tables | Pagination aktivieren bei grossen Datenmengen |
Zusammenfassung
Die Object Page bietet umfangreiche Anpassungsmöglichkeiten über CDS-Annotations:
- Header: Title, Subtitle, DataPoints, Contact Cards
- Sections/Tabs: Strukturierte Inhaltsorganisation mit
#COLLECTION - Field Groups: Formularlayout mit
#FIELDGROUP_REFERENCE - Inline Tables: Untergeordnete Entitäten mit
#LINEITEM_REFERENCE - Actions: Header-Actions, Section-Actions, Table-Actions
- Responsive:
importancefür adaptive Layouts
Die Kombination dieser Elemente ermöglicht professionelle Detail-Ansichten ohne UI5-Code.