RAP Feature Control: Dynamically Control UI Elements

Category
RAP
Published
Author
Johannes

Feature Control enables the dynamic control of UI elements in Fiori applications. You can enable, disable, or mark fields, actions, and operations as mandatory based on data state or authorizations.

Static vs. Dynamic Feature Control

RAP distinguishes between static (declarative) and dynamic (programmatic) Feature Control:

AspectStatic Feature ControlDynamic Feature Control
DefinitionIn Behavior DefinitionIn Behavior Implementation
EvaluationCompile timeRuntime
ContextAlways the sameInstance or global dependent
Examplefield ( readonly ) TravelIdfeatures: instance

Static Feature Control

Static features are declared directly in the Behavior Definition:

define behavior for ZI_Travel alias Travel
persistent table ztravel
lock master
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
// Static field features
field ( readonly ) TravelId; " Always read-only
field ( mandatory ) CustomerId; " Always mandatory
field ( readonly : update ) AgencyId; " Read-only only on update
field ( readonly ) CreatedBy, CreatedAt; " Admin fields
}

Dynamic Feature Control

Dynamic features are calculated at runtime:

define behavior for ZI_Travel alias Travel
{
// Operations with dynamic feature control
delete ( features: instance );
// Fields with dynamic feature control
field ( features: instance ) Status, Description;
// Actions with dynamic feature control
action ( features: instance ) acceptTravel result [1] $self;
action ( features: instance ) rejectTravel result [1] $self;
// Enable global feature control
static features;
}

Instance Feature Control

Instance Feature Control enables controlling features per instance based on their data state.

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.
" Read current instance data
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel)
FAILED failed.
" Set features per instance
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 only allowed for status 'Open'
%delete = COND #(
WHEN lv_is_open = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" Fields read-only or editable based on status
%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 only for 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 only for 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 Constants

ConstantTypeDescription
if_abap_behv=>fc-o-enabledOperationOperation enabled
if_abap_behv=>fc-o-disabledOperationOperation disabled
if_abap_behv=>fc-f-read_onlyFieldRead-only
if_abap_behv=>fc-f-mandatoryFieldMandatory
if_abap_behv=>fc-f-unrestrictedFieldNo restriction
if_abap_behv=>fc-f-mandatory_and_read_onlyFieldMandatory and read-only

Global Feature Control

Global Feature Control controls features independent of individual instances - typically based on authorizations or system states.

Behavior Definition

define behavior for ZI_Travel alias Travel
{
// Create with global feature control
create ( features: global );
// Static actions with global feature control
static action ( features: global ) massUpdate;
static action ( features: global ) importData;
// Enable global features
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.
" Authorization check
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 only with authorization
%create = COND #(
WHEN lv_has_create_auth = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" massUpdate only with change authorization
%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 for Standard Operations

Create, Update, Delete

define behavior for ZI_Travel alias Travel
{
// Static feature control
create; " Always allowed
update; " Always allowed
delete ( features: instance ); " Dynamic per instance
}
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 only for status Open or 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 only for status Open
%delete = COND #(
WHEN ls_travel-Status = 'O'
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
) ).
ENDMETHOD.

Interaction with Authorization

Feature Control and Authorization complement each other:

  • Authorization: Permission check - returns error on unauthorized access
  • Feature Control: UI control - prevents users from seeing disallowed actions
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.
" Authorization check
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).
" Check authorization for this 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: Based on status AND authorization
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).
" Check authorization
AUTHORITY-CHECK OBJECT 'Z_AGENCY'
ID 'AGENCY' FIELD ls_travel-AgencyId
ID 'ACTVT' FIELD '02'.
DATA(lv_has_auth) = xsdbool( sy-subrc = 0 ).
" Combination: Status Open AND authorization
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.

Dynamically Set Mandatory Fields

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 is mandatory for business trips
%field-CustomerId = COND #(
WHEN ls_travel-TravelType = 'B' " Business
THEN if_abap_behv=>fc-f-mandatory
ELSE if_abap_behv=>fc-f-unrestricted
)
" Approval is mandatory above certain amount
%field-ApproverId = COND #(
WHEN ls_travel-TotalPrice > 5000
THEN if_abap_behv=>fc-f-mandatory
ELSE if_abap_behv=>fc-f-unrestricted
)
) ).
ENDMETHOD.

Performance Optimization

Feature Control is called frequently. Optimize the implementation:

METHOD get_instance_features.
" 1. Only calculate needed features
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. Read minimal fields
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status ) " Only what's needed
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
" 3. Efficient loop
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 )
" ... more features
) ).
ENDMETHOD.

Best Practices

  1. Consistency: Feature Control and validations must be consistent - a disabled field should not be checked in a validation

  2. IN LOCAL MODE: Use IN LOCAL MODE to avoid authorization loops

  3. Minimal database access: Only read fields needed for the feature decision

  4. Global vs. Instance: Use Global Feature Control for authorization-based features, Instance for data-based

  5. Check requested features: Only calculate requested features for performance optimization

  6. Documentation: Document the feature logic so other developers understand why fields/actions are available when

Further Reading