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:
| Aspect | Static Feature Control | Dynamic Feature Control |
|---|---|---|
| Definition | In Behavior Definition | In Behavior Implementation |
| Evaluation | Compile time | Runtime |
| Context | Always the same | Instance or global dependent |
| Example | field ( readonly ) TravelId | features: instance |
Static Feature Control
Static features are declared directly in the Behavior Definition:
define behavior for ZI_Travel alias Travelpersistent table ztravellock masterauthorization 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
| Constant | Type | Description |
|---|---|---|
if_abap_behv=>fc-o-enabled | Operation | Operation enabled |
if_abap_behv=>fc-o-disabled | Operation | Operation disabled |
if_abap_behv=>fc-f-read_only | Field | Read-only |
if_abap_behv=>fc-f-mandatory | Field | Mandatory |
if_abap_behv=>fc-f-unrestricted | Field | No restriction |
if_abap_behv=>fc-f-mandatory_and_read_only | Field | Mandatory 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
-
Consistency: Feature Control and validations must be consistent - a disabled field should not be checked in a validation
-
IN LOCAL MODE: Use
IN LOCAL MODEto avoid authorization loops -
Minimal database access: Only read fields needed for the feature decision
-
Global vs. Instance: Use Global Feature Control for authorization-based features, Instance for data-based
-
Check requested features: Only calculate requested features for performance optimization
-
Documentation: Document the feature logic so other developers understand why fields/actions are available when
Further Reading
- RAP Side Effects - Automatic UI updates
- RAP Authorization - Authorization checks
- RAP Actions and Functions - Implementing business logic