RAP Feature Control: UI-Elemente dynamisch steuern

kategorie
RAP
Veröffentlicht
autor
Johannes

Feature Control ermöglicht die dynamische Steuerung von UI-Elementen in Fiori-Anwendungen. Du kannst Felder, Aktionen und Operationen basierend auf dem Datenzustand oder Berechtigungen aktivieren, deaktivieren oder als Pflichtfelder markieren.

Static vs. Dynamic Feature Control

RAP unterscheidet zwischen statischem (deklarativem) und dynamischem (programmatischem) Feature Control:

AspektStatic Feature ControlDynamic Feature Control
DefinitionIn Behavior DefinitionIn Behavior Implementation
AuswertungKompilierzeitLaufzeit
KontextImmer gleichInstanz- oder global abhängig
Beispielfield ( readonly ) TravelIdfeatures: instance

Static Feature Control

Statische Features werden direkt in der Behavior Definition deklariert:

define behavior for ZI_Travel alias Travel
persistent table ztravel
lock master
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
// Statische Feld-Features
field ( readonly ) TravelId; " Immer schreibgeschützt
field ( mandatory ) CustomerId; " Immer Pflichtfeld
field ( readonly : update ) AgencyId; " Nur beim Update readonly
field ( readonly ) CreatedBy, CreatedAt; " Admin-Felder
}

Dynamic Feature Control

Dynamische Features werden zur Laufzeit berechnet:

define behavior for ZI_Travel alias Travel
{
// Operationen mit dynamischem Feature Control
delete ( features: instance );
// Felder mit dynamischem Feature Control
field ( features: instance ) Status, Description;
// Aktionen mit dynamischem Feature Control
action ( features: instance ) acceptTravel result [1] $self;
action ( features: instance ) rejectTravel result [1] $self;
// Global Feature Control aktivieren
static features;
}

Instance Feature Control

Instance Feature Control ermöglicht die Steuerung von Features pro Instanz basierend auf deren Datenzustand.

Implementation

CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_features FOR INSTANCE FEATURES
IMPORTING keys REQUEST requested_features FOR Travel
RESULT result.
ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD get_instance_features.
" Aktuelle Instanzdaten lesen
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel)
FAILED failed.
" Features pro Instanz setzen
result = VALUE #( FOR ls_travel IN lt_travel
LET lv_is_open = xsdbool( ls_travel-Status = 'O' )
lv_is_accepted = xsdbool( ls_travel-Status = 'A' )
IN (
%tky = ls_travel-%tky
" Delete nur bei Status 'Open' erlaubt
%delete = COND #(
WHEN lv_is_open = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" Felder je nach Status readonly oder editierbar
%field-Status = COND #(
WHEN lv_is_open = abap_true
THEN if_abap_behv=>fc-f-unrestricted
ELSE if_abap_behv=>fc-f-read_only
)
%field-Description = COND #(
WHEN lv_is_open = abap_true
THEN if_abap_behv=>fc-f-unrestricted
ELSE if_abap_behv=>fc-f-read_only
)
" Accept-Action nur bei Status 'Open'
%action-acceptTravel = COND #(
WHEN lv_is_open = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" Reject-Action nur bei Status 'Accepted'
%action-rejectTravel = COND #(
WHEN lv_is_accepted = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
)
).
ENDMETHOD.
ENDCLASS.

Feature-Konstanten

KonstanteTypBeschreibung
if_abap_behv=>fc-o-enabledOperationOperation aktiviert
if_abap_behv=>fc-o-disabledOperationOperation deaktiviert
if_abap_behv=>fc-f-read_onlyFieldSchreibgeschützt
if_abap_behv=>fc-f-mandatoryFieldPflichtfeld
if_abap_behv=>fc-f-unrestrictedFieldKeine Einschränkung
if_abap_behv=>fc-f-mandatory_and_read_onlyFieldPflicht und readonly

Global Feature Control

Global Feature Control steuert Features unabhängig von einzelnen Instanzen – typischerweise basierend auf Berechtigungen oder Systemzuständen.

Behavior Definition

define behavior for ZI_Travel alias Travel
{
// Create mit Global Feature Control
create ( features: global );
// Static Actions mit Global Feature Control
static action ( features: global ) massUpdate;
static action ( features: global ) importData;
// Global Features aktivieren
static features;
}

Implementation

CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_global_features FOR GLOBAL FEATURES
IMPORTING REQUEST requested_features FOR Travel
RESULT result.
ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD get_global_features.
" Berechtigungsprüfung
AUTHORITY-CHECK OBJECT 'Z_TRAVEL'
ID 'ACTVT' FIELD '01'. " Create
DATA(lv_has_create_auth) = xsdbool( sy-subrc = 0 ).
AUTHORITY-CHECK OBJECT 'Z_TRAVEL'
ID 'ACTVT' FIELD '02'. " Change
DATA(lv_has_change_auth) = xsdbool( sy-subrc = 0 ).
result = VALUE #(
" Create nur mit Berechtigung
%create = COND #(
WHEN lv_has_create_auth = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" massUpdate nur mit Change-Berechtigung
%action-massUpdate = COND #(
WHEN lv_has_change_auth = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
).
ENDMETHOD.
ENDCLASS.

Features für Standardoperationen

Create, Update, Delete

define behavior for ZI_Travel alias Travel
{
// Static Feature Control
create; " Immer erlaubt
update; " Immer erlaubt
delete ( features: instance ); " Dynamisch pro Instanz
}
METHOD get_instance_features.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
result = VALUE #( FOR ls_travel IN lt_travel (
%tky = ls_travel-%tky
" Update nur bei Status Open oder Draft
%update = COND #(
WHEN ls_travel-Status = 'O' OR ls_travel-Status = 'D'
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" Delete nur bei Status Open
%delete = COND #(
WHEN ls_travel-Status = 'O'
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
) ).
ENDMETHOD.

Zusammenspiel mit Authorization

Feature Control und Authorization ergänzen sich:

  • Authorization: Berechtigungsprüfung – liefert Fehler bei unberechtigtem Zugriff
  • Feature Control: UI-Steuerung – verhindert, dass Benutzer nicht erlaubte Aktionen sehen
CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR Travel
RESULT result.
METHODS get_instance_features FOR INSTANCE FEATURES
IMPORTING keys REQUEST requested_features FOR Travel
RESULT result.
ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD get_instance_authorizations.
" Berechtigungsprüfung
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( AgencyId )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
LOOP AT lt_travel INTO DATA(ls_travel).
" Prüfe Berechtigung für diese Agency
AUTHORITY-CHECK OBJECT 'Z_AGENCY'
ID 'AGENCY' FIELD ls_travel-AgencyId
ID 'ACTVT' FIELD '02'.
DATA(lv_authorized) = xsdbool( sy-subrc = 0 ).
APPEND VALUE #(
%tky = ls_travel-%tky
%update = COND #( WHEN lv_authorized = abap_true
THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized )
%delete = COND #( WHEN lv_authorized = abap_true
THEN if_abap_behv=>auth-allowed
ELSE if_abap_behv=>auth-unauthorized )
) TO result.
ENDLOOP.
ENDMETHOD.
METHOD get_instance_features.
" Feature Control: Basierend auf Status UND Berechtigung
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status AgencyId )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
LOOP AT lt_travel INTO DATA(ls_travel).
" Berechtigung prüfen
AUTHORITY-CHECK OBJECT 'Z_AGENCY'
ID 'AGENCY' FIELD ls_travel-AgencyId
ID 'ACTVT' FIELD '02'.
DATA(lv_has_auth) = xsdbool( sy-subrc = 0 ).
" Kombination: Status Open UND Berechtigung
DATA(lv_can_edit) = xsdbool( ls_travel-Status = 'O' AND lv_has_auth = abap_true ).
APPEND VALUE #(
%tky = ls_travel-%tky
%delete = COND #( WHEN lv_can_edit = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
%field-Description = COND #( WHEN lv_can_edit = abap_true
THEN if_abap_behv=>fc-f-unrestricted
ELSE if_abap_behv=>fc-f-read_only )
) TO result.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Mandatory-Felder dynamisch setzen

METHOD get_instance_features.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status TravelType )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
result = VALUE #( FOR ls_travel IN lt_travel (
%tky = ls_travel-%tky
" CustomerID ist Pflicht bei Business-Reisen
%field-CustomerId = COND #(
WHEN ls_travel-TravelType = 'B' " Business
THEN if_abap_behv=>fc-f-mandatory
ELSE if_abap_behv=>fc-f-unrestricted
)
" Approval ist Pflicht ab gewissem Betrag
%field-ApproverId = COND #(
WHEN ls_travel-TotalPrice > 5000
THEN if_abap_behv=>fc-f-mandatory
ELSE if_abap_behv=>fc-f-unrestricted
)
) ).
ENDMETHOD.

Performance-Optimierung

Feature Control wird häufig aufgerufen. Optimiere die Implementierung:

METHOD get_instance_features.
" 1. Nur benötigte Features berechnen
CHECK requested_features-%delete = if_abap_behv=>mk-on
OR requested_features-%action-acceptTravel = if_abap_behv=>mk-on
OR requested_features-%field-Status = if_abap_behv=>mk-on.
" 2. Minimale Felder lesen
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status ) " Nur was benötigt wird
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
" 3. Effiziente Schleife
result = VALUE #( FOR ls_travel IN lt_travel (
%tky = ls_travel-%tky
%delete = COND #( WHEN ls_travel-Status = 'O'
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
" ... weitere Features
) ).
ENDMETHOD.

Best Practices

  1. Konsistenz: Feature Control und Validierungen müssen konsistent sein – ein deaktiviertes Feld sollte nicht in einer Validation geprüft werden

  2. IN LOCAL MODE: Verwende IN LOCAL MODE um Authorization-Loops zu vermeiden

  3. Minimale Datenbankzugriffe: Lese nur die Felder, die du für die Feature-Entscheidung brauchst

  4. Global vs. Instance: Nutze Global Feature Control für berechtigungsbasierte Features, Instance für datenbasierte

  5. Requested Features prüfen: Berechne nur angeforderte Features zur Performance-Optimierung

  6. Dokumentation: Dokumentiere die Feature-Logik, damit andere Entwickler verstehen, warum Felder/Aktionen wann verfügbar sind

Weiterführende Themen