Willkommen zu Teil 2 der RAP Tutorial-Serie! In Teil 1 hast du eine funktionierende Fiori App gebaut. Jetzt machen wir sie richtig smart mit Business-Logik.
🎯 Was du lernen wirst
- Actions: Custom Buttons für Geschäftsoperationen
- Validations: Datenprüfung (z.B. ISBN-Format)
- Determinations: Automatische Werte setzen
- Value Helps: Dropdown-Listen
- Feature Control: Buttons dynamisch ein/ausblenden
Basis: Wir bauen auf der Book Management App aus Teil 1 auf.
Geschätzte Zeit: 45-60 Minuten
📋 Voraussetzungen
- ✅ Teil 1 abgeschlossen
- ✅ Book Management App läuft
- ✅ ADT (Eclipse) geöffnet
Feature 1: Status-Management mit Actions
Wir fügen einen Status hinzu (New, Reading, Finished) und Actions zum Ändern des Status.
Schritt 1: Tabelle erweitern
Öffne ZBOOK_TAB und füge hinzu:
define table zbook_tab { // ... bestehende Felder ...
status : abap.char(1); // N=New, R=Reading, F=Finished
// ... created_by, etc. ...}Aktivieren: Ctrl+F3
Schritt 2: CDS Views erweitern
In ZI_BOOK:
define root view entity ZI_BOOK as select from zbook_tab{ // ... bestehende Felder ...
status as Status,
// Status-Text via Association case status when 'N' then 'Neu' when 'R' then 'Lese ich gerade' when 'F' then 'Gelesen' else 'Unbekannt' end as StatusText,
// ... created_by, etc. ...}In ZC_BOOK:
define root view entity ZC_BOOK as projection on ZI_BOOK{ // ... bestehende Felder ...
@ObjectModel.text.element: ['StatusText'] Status, StatusText,
// ... created_by, etc. ...}Beide aktivieren!
Schritt 3: Behavior Definition erweitern - Actions hinzufügen
Öffne die Interface BDEF (ZI_BOOK → Behavior Definition):
managed implementation in class zbp_i_book unique;strict ( 2 );
define behavior for ZI_BOOK alias Bookpersistent table zbook_tablock masterauthorization master ( instance )etag master LastChangedAt{ create; update; delete;
field ( readonly ) BookId; field ( readonly ) CreatedBy, CreatedAt, LastChangedBy, LastChangedAt; field ( numbering : managed ) BookId;
// ⭐ NEU: Actions mit Feature Control action ( features : instance ) startReading result [1] $self; action ( features : instance ) markAsFinished result [1] $self; action ( features : instance ) resetStatus result [1] $self;
// ⭐ NEU: Validation beim Speichern validation validateIsbn on save { field Isbn; } validation validatePages on save { field Pages; }
// ⭐ NEU: Determination bei Create determination setDefaultStatus on modify { create; }
mapping for zbook_tab { BookId = book_id; Title = title; Author = author; Publisher = publisher; Isbn = isbn; Price = price; CurrencyCode = currency_code; Pages = pages; PublicationYear = publication_year; Language = language; Status = status; // NEU CreatedBy = created_by; CreatedAt = created_at; LastChangedBy = last_changed_by; LastChangedAt = last_changed_at; }}Aktivieren: Ctrl+F3
Schritt 4: Projection BDEF erweitern
Öffne ZC_BOOK Behavior Definition:
projection;strict ( 2 );
define behavior for ZC_BOOK alias Book{ use create; use update; use delete;
// ⭐ NEU: Actions exposen use action startReading; use action markAsFinished; use action resetStatus;}Aktivieren!
Schritt 5: Behavior Implementation - Actions implementieren
ADT hat automatisch ZBP_I_BOOK erstellt. Öffne die Klasse und füge hinzu:
Local Types (am Ende der Klasse):
CLASS lhc_book DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS: " Feature Control (welche Actions verfügbar?) get_instance_features FOR INSTANCE FEATURES IMPORTING keys REQUEST requested_features FOR Book RESULT result,
" Actions startReading FOR MODIFY IMPORTING keys FOR ACTION Book~startReading RESULT result,
markAsFinished FOR MODIFY IMPORTING keys FOR ACTION Book~markAsFinished RESULT result,
resetStatus FOR MODIFY IMPORTING keys FOR ACTION Book~resetStatus RESULT result,
" Validations validateIsbn FOR VALIDATE ON SAVE IMPORTING keys FOR Book~validateIsbn,
validatePages FOR VALIDATE ON SAVE IMPORTING keys FOR Book~validatePages,
" Determinations setDefaultStatus FOR DETERMINE ON MODIFY IMPORTING keys FOR Book~setDefaultStatus.ENDCLASS.
CLASS lhc_book IMPLEMENTATION.
" ===== FEATURE CONTROL ===== METHOD get_instance_features. " Lese aktuelle Bücher READ ENTITIES OF zi_book IN LOCAL MODE ENTITY Book FIELDS ( Status ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_books) FAILED failed.
" Feature Control basierend auf Status result = VALUE #( FOR ls_book IN lt_books ( %tky = ls_book-%tky
" startReading: Nur verfügbar wenn Status = 'N' (Neu) %features-%action-startReading = COND #( WHEN ls_book-Status = 'N' THEN if_abap_behv=>fc-o-enabled ELSE if_abap_behv=>fc-o-disabled )
" markAsFinished: Nur verfügbar wenn Status = 'R' (Reading) %features-%action-markAsFinished = COND #( WHEN ls_book-Status = 'R' THEN if_abap_behv=>fc-o-enabled ELSE if_abap_behv=>fc-o-disabled )
" resetStatus: Immer verfügbar außer bei 'N' %features-%action-resetStatus = COND #( WHEN ls_book-Status <> 'N' THEN if_abap_behv=>fc-o-enabled ELSE if_abap_behv=>fc-o-disabled ) ) ). ENDMETHOD.
" ===== ACTIONS ===== METHOD startReading. " Status auf 'R' (Reading) setzen MODIFY ENTITIES OF zi_book IN LOCAL MODE ENTITY Book UPDATE FIELDS ( Status ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky Status = 'R' ) ) FAILED failed REPORTED reported.
" Aktualisierte Bücher zurückgeben READ ENTITIES OF zi_book IN LOCAL MODE ENTITY Book ALL FIELDS WITH CORRESPONDING #( keys ) RESULT result. ENDMETHOD.
METHOD markAsFinished. " Status auf 'F' (Finished) setzen MODIFY ENTITIES OF zi_book IN LOCAL MODE ENTITY Book UPDATE FIELDS ( Status ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky Status = 'F' ) ) FAILED failed REPORTED reported.
READ ENTITIES OF zi_book IN LOCAL MODE ENTITY Book ALL FIELDS WITH CORRESPONDING #( keys ) RESULT result. ENDMETHOD.
METHOD resetStatus. " Status auf 'N' (New) zurücksetzen MODIFY ENTITIES OF zi_book IN LOCAL MODE ENTITY Book UPDATE FIELDS ( Status ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky Status = 'N' ) ) FAILED failed REPORTED reported.
READ ENTITIES OF zi_book IN LOCAL MODE ENTITY Book ALL FIELDS WITH CORRESPONDING #( keys ) RESULT result. ENDMETHOD.
" ===== VALIDATIONS ===== METHOD validateIsbn. " Bücher lesen READ ENTITIES OF zi_book IN LOCAL MODE ENTITY Book FIELDS ( Isbn ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_books).
LOOP AT lt_books INTO DATA(ls_book). " ISBN muss 10 oder 13 Zeichen lang sein DATA(lv_isbn_length) = strlen( ls_book-Isbn ).
IF lv_isbn_length <> 10 AND lv_isbn_length <> 13. APPEND VALUE #( %tky = ls_book-%tky %element-Isbn = if_abap_behv=>mk-on ) TO failed-book.
APPEND VALUE #( %tky = ls_book-%tky %element-Isbn = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'ISBN muss 10 oder 13 Zeichen lang sein' ) ) TO reported-book. ENDIF.
" ISBN darf nur Ziffern enthalten (vereinfachte Prüfung) IF ls_book-Isbn IS NOT INITIAL AND ls_book-Isbn CO '0123456789' = abap_false. APPEND VALUE #( %tky = ls_book-%tky %element-Isbn = if_abap_behv=>mk-on ) TO failed-book.
APPEND VALUE #( %tky = ls_book-%tky %element-Isbn = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'ISBN darf nur Ziffern enthalten' ) ) TO reported-book. ENDIF. ENDLOOP. ENDMETHOD.
METHOD validatePages. READ ENTITIES OF zi_book IN LOCAL MODE ENTITY Book FIELDS ( Pages ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_books).
LOOP AT lt_books INTO DATA(ls_book). " Seiten müssen > 0 sein IF ls_book-Pages IS NOT INITIAL AND ls_book-Pages <= 0. APPEND VALUE #( %tky = ls_book-%tky %element-Pages = if_abap_behv=>mk-on ) TO failed-book.
APPEND VALUE #( %tky = ls_book-%tky %element-Pages = if_abap_behv=>mk-on %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'Seitenzahl muss größer als 0 sein' ) ) TO reported-book. ENDIF. ENDLOOP. ENDMETHOD.
" ===== DETERMINATIONS ===== METHOD setDefaultStatus. " Lese neu angelegte Bücher READ ENTITIES OF zi_book IN LOCAL MODE ENTITY Book FIELDS ( Status ) WITH CORRESPONDING #( keys ) RESULT DATA(lt_books).
" Setze Default-Status auf 'N' (New) MODIFY ENTITIES OF zi_book IN LOCAL MODE ENTITY Book UPDATE FIELDS ( Status ) WITH VALUE #( FOR ls_book IN lt_books WHERE ( Status IS INITIAL ) ( %tky = ls_book-%tky Status = 'N' ) ) REPORTED reported. ENDMETHOD.
ENDCLASS.Aktivieren: Ctrl+F3
Schritt 6: UI-Annotations für Actions
Öffne die Metadata Extension (ZC_BOOK):
@Metadata.layer: #CORE
annotate view ZC_BOOK with{ @UI.headerInfo: { typeName: 'Buch', typeNamePlural: 'Bücher', title: { value: 'Title' }, description: { value: 'Author' } }
@UI.facet: [ { id: 'BookDetails', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Buch-Details', position: 10 } ]
// ⭐ NEU: Actions in der Liste @UI.lineItem: [ { position: 10, importance: #HIGH }, { type: #FOR_ACTION, dataAction: 'startReading', label: 'Lesen starten' }, { type: #FOR_ACTION, dataAction: 'markAsFinished', label: 'Als gelesen markieren' }, { type: #FOR_ACTION, dataAction: 'resetStatus', label: 'Status zurücksetzen' } ] @UI.identification: [{ position: 10 }] @UI.selectionField: [{ position: 10 }] BookId;
@UI.lineItem: [{ position: 20, importance: #HIGH }] @UI.identification: [{ position: 20 }] @UI.selectionField: [{ position: 20 }] Title;
@UI.lineItem: [{ position: 30, importance: #HIGH }] @UI.identification: [{ position: 30 }] @UI.selectionField: [{ position: 30 }] Author;
@UI.lineItem: [{ position: 40 }] @UI.identification: [{ position: 40 }] Publisher;
@UI.identification: [{ position: 50 }] Isbn;
@UI.lineItem: [{ position: 50 }] @UI.identification: [{ position: 60 }] Price;
@UI.identification: [{ position: 70 }] Pages;
@UI.lineItem: [{ position: 60 }] @UI.identification: [{ position: 80 }] PublicationYear;
@UI.identification: [{ position: 90 }] Language;
// ⭐ NEU: Status anzeigen @UI.lineItem: [{ position: 35, importance: #HIGH, criticality: 'Status' }] @UI.identification: [{ position: 35 }] @UI.selectionField: [{ position: 40 }] Status;}Aktivieren!
Schritt 7: Service Binding neu publishen
- Öffne
ZUI_BOOK_O4(Service Binding) - Unpublish klicken
- Publish klicken
Schritt 8: Testen! 🎉
- Preview öffnen
- Buch erstellen
- Buttons erscheinen:
- “Lesen starten” (nur bei Status = Neu)
- “Als gelesen markieren” (nur bei Status = Lese ich gerade)
- “Status zurücksetzen” (nicht bei Neu)
Probiere es aus:
- Klicke “Lesen starten” → Status ändert sich zu “Lese ich gerade”
- Jetzt erscheint “Als gelesen markieren”
- Validierung testen: Gib ISBN mit Buchstaben ein → Fehler!
Feature 2: Value Help (Dropdown für Status)
Aktuell muss man den Status manuell eingeben. Besser: Dropdown mit Auswahl!
Schritt 1: Domain Fixed Values erstellen
In ZC_BOOK Metadata Extension:
annotate view ZC_BOOK with{ // ... andere Felder ...
@UI.lineItem: [{ position: 35, importance: #HIGH }] @UI.identification: [{ position: 35 }] @UI.selectionField: [{ position: 40 }] @Consumption.valueHelpDefinition: [{ entity: { name: 'I_Status_VH', element: 'StatusCode' } }] Status;}Besser: Custom Value Help via CDS View
Erstelle neue Data Definition ZI_BOOK_STATUS_VH:
@AccessControl.authorizationCheck: #NOT_REQUIRED@EndUserText.label: 'Value Help für Buch-Status'
define view entity ZI_BOOK_STATUS_VH as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'ZBOOK_STATUS' ){ @ObjectModel.text.element: ['Description'] key domain_name as DomainName, key value_position as ValuePosition, @Semantics.language: true key language as Language, value_low as StatusCode, text as Description}Alternativ: Einfachere Version ohne Domain
@AccessControl.authorizationCheck: #NOT_REQUIRED@EndUserText.label: 'Book Status Value Help'
define view entity ZI_BOOK_STATUS_VH as select from I_Language{ key 'N' as StatusCode, cast( 'Neu' as abap.char(20) ) as StatusText}union select from I_Language{ key 'R' as StatusCode, cast( 'Lese ich gerade' as abap.char(20) ) as StatusText}union select from I_Language{ key 'F' as StatusCode, cast( 'Gelesen' as abap.char(20) ) as StatusText}Aktivieren und in Metadata Extension referenzieren:
@Consumption.valueHelpDefinition: [{ entity: { name: 'ZI_BOOK_STATUS_VH', element: 'StatusCode' }}]Status;🎯 Was haben wir gelernt?
Actions
- Definition:
action startReading result [1] $self; - Feature Control: Buttons dynamisch verfügbar machen
- Implementation:
MODIFY ENTITIESzum Status ändern - UI: Actions in
@UI.lineItemanzeigen
Validations
- Wann:
on save(vor Speichern) oderon modify(sofort) - Felder prüfen: ISBN-Format, Seitenzahl > 0
- Fehler melden:
failed+reportedbefüllen - UI: Felder rot markieren, Fehlermeldung anzeigen
Determinations
- Wann:
on modify { create; }(bei Anlage) - Zweck: Default-Werte setzen (z.B. Status = ‘N’)
- Implementation:
MODIFY ENTITIESzum Setzen
Feature Control
- Dynamische Buttons: Basierend auf Daten (z.B. Status)
- Method:
get_instance_features - Logik:
if_abap_behv=>fc-o-enabledvs.disabled
🚀 Nächste Schritte
- Performance-Optimierung (SELECT Performance, EML Batching)
- Error Handling & Logging
- Unit Testing für RAP
- Deployment & Versionierung
- Häufige Fehler vermeiden
📚 Code-Übersicht
Neue/Geänderte Objekte:
- ✅
ZBOOK_TAB(Status-Feld hinzugefügt) - ✅
ZI_BOOK(Status, StatusText) - ✅
ZC_BOOK(Status exposen) - ✅ BDEF Interface (Actions, Validations, Determinations)
- ✅ BDEF Projection (Actions exposen)
- ✅
ZBP_I_BOOK(Implementation) - ✅ Metadata Extension (UI-Annotations für Actions)
💬 Fragen?
- Funktionieren die Actions?
- Validations werden korrekt angezeigt?
- Welche Business-Logik möchtest du noch hinzufügen?
Weiter mit Teil 3: Best Practices →