RAP Feature Control: Controlar elementos UI dinámicamente

Kategorie
RAP
Veröffentlicht
Autor
Johannes

Feature Control permite el control dinámico de elementos UI en aplicaciones Fiori. Puedes activar, desactivar campos, acciones y operaciones o marcarlas como obligatorias basándote en el estado de los datos o permisos.

Static vs. Dynamic Feature Control

RAP distingue entre Feature Control estático (declarativo) y dinámico (programático):

AspectoStatic Feature ControlDynamic Feature Control
DefiniciónEn Behavior DefinitionEn Behavior Implementation
EvaluaciónTiempo de compilaciónTiempo de ejecución
ContextoSiempre igualDependiente de instancia o global
Ejemplofield ( readonly ) TravelIdfeatures: instance

Static Feature Control

Las características estáticas se declaran directamente en la Behavior Definition:

define behavior for ZI_Travel alias Travel
persistent table ztravel
lock master
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
// Features de campo estáticos
field ( readonly ) TravelId; " Siempre solo lectura
field ( mandatory ) CustomerId; " Siempre obligatorio
field ( readonly : update ) AgencyId; " Solo lectura en update
field ( readonly ) CreatedBy, CreatedAt; " Campos admin
}

Dynamic Feature Control

Las características dinámicas se calculan en tiempo de ejecución:

define behavior for ZI_Travel alias Travel
{
// Operaciones con Feature Control dinámico
delete ( features: instance );
// Campos con Feature Control dinámico
field ( features: instance ) Status, Description;
// Acciones con Feature Control dinámico
action ( features: instance ) acceptTravel result [1] $self;
action ( features: instance ) rejectTravel result [1] $self;
// Activar Global Feature Control
static features;
}

Instance Feature Control

Instance Feature Control permite controlar características por instancia basándose en su estado de datos.

Implementación

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.
" Leer datos de instancia actual
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel)
FAILED failed.
" Establecer features por instancia
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 solo permitido con Status 'Open'
%delete = COND #(
WHEN lv_is_open = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" Campos readonly o editables según estado
%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 solo con 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 solo con 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.

Constantes de Feature

ConstanteTipoDescripción
if_abap_behv=>fc-o-enabledOperationOperación activada
if_abap_behv=>fc-o-disabledOperationOperación desactivada
if_abap_behv=>fc-f-read_onlyFieldSolo lectura
if_abap_behv=>fc-f-mandatoryFieldCampo obligatorio
if_abap_behv=>fc-f-unrestrictedFieldSin restricción
if_abap_behv=>fc-f-mandatory_and_read_onlyFieldObligatorio y readonly

Global Feature Control

Global Feature Control controla características independientemente de instancias individuales - típicamente basado en permisos o estados del sistema.

Behavior Definition

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

Implementación

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.
" Verificación de permisos
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 solo con permiso
%create = COND #(
WHEN lv_has_create_auth = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
" massUpdate solo con permiso Change
%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 para operaciones estándar

Create, Update, Delete

define behavior for ZI_Travel alias Travel
{
// Static Feature Control
create; " Siempre permitido
update; " Siempre permitido
delete ( features: instance ); " Dinámico por instancia
}
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 solo con Status Open o 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 solo con Status Open
%delete = COND #(
WHEN ls_travel-Status = 'O'
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled
)
) ).
ENDMETHOD.

Interacción con Authorization

Feature Control y Authorization se complementan:

  • Authorization: Verificación de permisos - devuelve error en acceso no autorizado
  • Feature Control: Control de UI - evita que usuarios vean acciones no permitidas
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.
" Verificación de permisos
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).
" Verificar permiso para esta 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: Basado en Status Y permisos
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).
" Verificar permiso
AUTHORITY-CHECK OBJECT 'Z_AGENCY'
ID 'AGENCY' FIELD ls_travel-AgencyId
ID 'ACTVT' FIELD '02'.
DATA(lv_has_auth) = xsdbool( sy-subrc = 0 ).
" Combinación: Status Open Y permiso
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.

Establecer campos obligatorios dinámicamente

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 es obligatorio en viajes de negocios
%field-CustomerId = COND #(
WHEN ls_travel-TravelType = 'B' " Business
THEN if_abap_behv=>fc-f-mandatory
ELSE if_abap_behv=>fc-f-unrestricted
)
" Approval es obligatorio a partir de cierto monto
%field-ApproverId = COND #(
WHEN ls_travel-TotalPrice > 5000
THEN if_abap_behv=>fc-f-mandatory
ELSE if_abap_behv=>fc-f-unrestricted
)
) ).
ENDMETHOD.

Optimización de rendimiento

Feature Control se llama frecuentemente. Optimiza la implementación:

METHOD get_instance_features.
" 1. Calcular solo features necesarios
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. Leer campos mínimos
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status ) " Solo lo necesario
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
" 3. Bucle eficiente
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 )
" ... más features
) ).
ENDMETHOD.

Mejores prácticas

  1. Consistencia: Feature Control y Validations deben ser consistentes - un campo desactivado no debería verificarse en una Validation

  2. IN LOCAL MODE: Usa IN LOCAL MODE para evitar loops de Authorization

  3. Accesos mínimos a base de datos: Lee solo los campos que necesitas para la decisión de features

  4. Global vs. Instance: Usa Global Feature Control para features basados en permisos, Instance para basados en datos

  5. Verificar Requested Features: Calcula solo features solicitados para optimización de rendimiento

  6. Documentación: Documenta la lógica de features para que otros desarrolladores entiendan cuándo están disponibles campos/acciones

Temas relacionados