Feature Control & Side Effects dans RAP : Contrôle dynamique de l'UI

Catégorie
RAP
Publié
Auteur
Johannes

Le Feature Control permet le contrôle dynamique des éléments UI comme les champs, actions et opérations en fonction de l’état actuel des données. Les Side Effects assurent les mises à jour automatiques de l’UI lorsque les valeurs des champs changent.

Pourquoi le Feature Control ?

Le Feature Control répond à des questions telles que :

  • L’utilisateur peut-il supprimer cette instance ?
  • Ce champ doit-il être en lecture seule ?
  • Cette action est-elle disponible pour le statut actuel ?
  • L’utilisateur peut-il modifier les associations ?

Instance vs. Global Feature Control

AspectInstance Feature ControlGlobal Feature Control
PortéePar instancePour toutes les instances
ÉvaluationPour chaque instance individuellementUne fois pour l’entité
Cas d’usageFonctionnalités dépendantes du statutFonctionnalités dépendantes des autorisations
PerformancePlus élevée (n appels)Plus faible (1 appel)
Exemple”Annuler uniquement si statut Ouvert""Create uniquement avec autorisation”

Behavior Definition avec Feature Control

Les Features sont déclarées dans la Behavior Definition :

managed implementation in class zbp_i_travel unique;
strict ( 2 );
define behavior for ZI_Travel alias Travel
persistent table ztravel
lock master
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete ( features: instance );
// Felder mit Feature Control
field ( readonly ) TravelID;
field ( features: instance ) Status, Description;
// Aktionen mit Feature Control
action ( features: instance ) cancel;
action ( features: instance ) accept;
// Globales Feature Control für Create
static features;
}

Options de Feature

DéclarationSignification
features: instanceDynamique par instance
features: globalDynamique global (pour static actions)
readonlyToujours en lecture seule
mandatoryChamp obligatoire
readonly:updateEn lecture seule uniquement lors de la mise à jour

Implémentation d’Instance Feature Control

La méthode get_instance_features détermine les Features par instance :

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 Daten lesen
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status BeginDate )
WITH CORRESPONDING #( keys )
RESULT DATA(travels).
" Features pro Instanz setzen
result = VALUE #( FOR travel IN travels
LET is_open = COND #( WHEN travel-Status = 'O' THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
is_accepted = COND #( WHEN travel-Status = 'A' THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
is_readonly = COND #( WHEN travel-Status <> 'O' THEN if_abap_behv=>fc-f-read_only
ELSE if_abap_behv=>fc-f-unrestricted )
IN (
%tky = travel-%tky
" Operations
%delete = is_open
" Fields
%field-Status = is_readonly
%field-Description = is_readonly
" Actions
%action-cancel = is_open
%action-accept = is_open
)
).
ENDMETHOD.
ENDCLASS.

Constantes de Feature

ConstanteTypeSignification
if_abap_behv=>fc-o-enabledOperationActivé
if_abap_behv=>fc-o-disabledOperationDésactivé
if_abap_behv=>fc-f-read_onlyFieldLecture seule
if_abap_behv=>fc-f-mandatoryFieldObligatoire
if_abap_behv=>fc-f-unrestrictedFieldAucune restriction
if_abap_behv=>fc-f-mandatory_and_read_onlyFieldObligatoire et readonly

Global Feature Control

Le Global Feature Control contrôle les Features indépendamment des instances individuelles :

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 für Create
DATA(has_create_auth) = check_create_authorization( ).
" Prüfen ob heute ein Arbeitstag ist
DATA(is_workday) = check_workday( ).
result = VALUE #(
" Create nur mit Berechtigung
%create = COND #( WHEN has_create_auth = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
" Static Action nur an Arbeitstagen
%action-massUpdate = COND #( WHEN is_workday = abap_true
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
).
ENDMETHOD.
ENDCLASS.

Static Actions avec Feature Control

define behavior for ZI_Travel alias Travel
{
// Static Action mit Global Feature Control
static action ( features: global ) massUpdate result [1] $self;
static action ( features: global ) generateReport;
// Reguläre Features
static features;
}

Side Effects : Mises à jour automatiques de l’UI

Les Side Effects définissent quelles parties de l’UI doivent être actualisées lorsque les valeurs des champs changent.

Side Effects dans la Behavior Definition

define behavior for ZI_Travel alias Travel
{
// Side Effect: Wenn BeginDate oder EndDate sich ändert, berechne Duration
side effects
{
field BeginDate affects field Duration;
field EndDate affects field Duration;
// Mehrere Felder beeinflussen ein Zielfeld
field ( BeginDate, EndDate ) affects field Duration, field TotalPrice;
// Feld beeinflusst gesamte Entität
field Currency affects entity;
// Determination triggert Side Effect
determine action calculatePrice executed on field BeginDate affects field TotalPrice;
}
}

Side Effects pour les associations

define behavior for ZI_Travel alias Travel
{
side effects
{
// Änderungen an Child-Entitäten beeinflussen Parent
field _Bookings affects field TotalPrice;
// Feld in Parent beeinflusst Children
field Currency affects entity _Bookings;
}
}

Side Effects pour les Actions

define behavior for ZI_Travel alias Travel
{
action recalculate;
side effects
{
// Nach Aktion werden diese Felder aktualisiert
action recalculate affects field TotalPrice, field Status;
// Aktion beeinflusst gesamte Entität und Assoziationen
action copyTravel affects entity, entity _Bookings;
}
}

Exemples combinés

Champs et actions dépendants du statut

METHOD get_instance_features.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status TravelID )
WITH CORRESPONDING #( keys )
RESULT DATA(travels).
result = VALUE #( FOR travel IN travels (
%tky = travel-%tky
" Status Open: Alles editierbar
%field-BeginDate = COND #( WHEN travel-Status = 'O"
THEN if_abap_behv=>fc-f-unrestricted
ELSE if_abap_behv=>fc-f-read_only )
%field-EndDate = COND #( WHEN travel-Status = 'O"
THEN if_abap_behv=>fc-f-unrestricted
ELSE if_abap_behv=>fc-f-read_only )
%field-CustomerID = COND #( WHEN travel-Status = 'O"
THEN if_abap_behv=>fc-f-mandatory
ELSE if_abap_behv=>fc-f-read_only )
" Delete nur bei Status Open
%delete = COND #( WHEN travel-Status = 'O"
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
" Accept nur bei Status Open
%action-accept = COND #( WHEN travel-Status = 'O"
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
" Reject nur bei Status Accepted
%action-reject = COND #( WHEN travel-Status = 'A"
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
) ).
ENDMETHOD.

Side Effects avec Determination

define behavior for ZI_Travel alias Travel
{
// Determination für Preisberechnung
determination calculatePrice on modify { field BeginDate; field EndDate; }
side effects
{
// Wenn Determination ausgeführt wird, aktualisiere TotalPrice in UI
determine action calculatePrice executed on field BeginDate
affects field TotalPrice, field Currency;
determine action calculatePrice executed on field EndDate
affects field TotalPrice;
}
}

Dépendances de champs dans la Projection

Dans la Projection, des annotations UI supplémentaires peuvent être définies :

define root view entity ZC_Travel
provider contract transactional_query
as projection on ZI_Travel
{
@UI.hidden: true
key TravelUUID,
@UI.identification: [{ position: 10 }]
@UI.lineItem: [{ position: 10 }]
TravelID,
@UI.identification: [{ position: 20, criticality: 'StatusCriticality' }]
Status,
// Dynamische Sichtbarkeit über Hidden-Binding
@UI.hidden: 'HideInternalNote"
InternalNote,
// Calculated Field für Criticality
case Status
when 'O' then 3 " Green
when 'A' then 2 " Yellow
when 'X' then 1 " Red
end as StatusCriticality
}

Bonnes pratiques

  1. Attention à la performance : Instance Feature Control est appelé pour chaque instance. Minimisez les accès à la base de données.

  2. Utiliser READ ENTITIES : Utilisez IN LOCAL MODE pour éviter les vérifications d’autorisation.

  3. Logique cohérente : Assurez-vous que Feature Control et validations sont cohérents.

  4. Utiliser Side Effects de manière ciblée : Trop de Side Effects peuvent affecter la performance.

  5. Vérifier les Features demandées : Calculer uniquement les Features demandées :

METHOD get_instance_features.
" Nur berechnen wenn angefordert
CHECK requested_features-%delete = if_abap_behv=>mk-on OR
requested_features-%action-cancel = if_abap_behv=>mk-on.
" ... Feature-Berechnung
ENDMETHOD.
  1. Features globales pour les autorisations : Utilisez Global Feature Control pour les restrictions basées sur les autorisations.

Sujets avancés