Parfois, un simple clic sur un bouton ne suffit pas. Avant d’annuler une réservation, l’utilisateur doit indiquer une raison. Avant un transfert, de nouvelles données doivent être saisies. Les Actions Popup dans RAP permettent exactement cela : des saisies utilisateur structurées avant l’exécution d’une action.
Le concept : Action avec entité de paramètres
Une action popup se compose de trois composants :
- Abstract Entity : Définit la structure du popup (champs, types de données)
- Behavior Definition : Lie l’action au paramètre
- Implementation : Traite les valeurs saisies
┌─────────────────────────────────────────────────────────────────┐│ Annuler la réservation [X] │├─────────────────────────────────────────────────────────────────┤│ ││ Raison de l'annulation * ││ ┌─────────────────────────────────────┐ ││ │ Modification client ▼ │ ││ └─────────────────────────────────────┘ ││ ││ Remarque ││ ┌─────────────────────────────────────┐ ││ │ Client a réservé un vol ultérieur │ ││ │ vers Munich. │ ││ └─────────────────────────────────────┘ ││ ││ ☑ Notifier le client par e-mail ││ ││ Montant du remboursement ││ ┌───────────────┐ EUR ││ │ 450,00 │ ││ └───────────────┘ ││ ││ [ Annuler ] [ Valider ] │└─────────────────────────────────────────────────────────────────┘Étape 1 : Définir l’Abstract Entity
L’Abstract Entity décrit les champs du dialogue popup :
@EndUserText.label: 'Données d\'annulation"define abstract entity ZA_CancelBookingParams{ @EndUserText.label: 'Raison de l\'annulation" @Consumption.valueHelpDefinition: [{ entity: { name: 'ZI_CancellationReasonVH', element: 'ReasonCode' } }] CancellationReason : abap.char(2);
@EndUserText.label: 'Remarque" @UI.multiLineText: true Remarks : abap.string(500);
@EndUserText.label: 'Notifier le client" NotifyCustomer : abap_boolean;
@EndUserText.label: 'Montant du remboursement" @Semantics.amount.currencyCode: 'Currency" RefundAmount : abap.curr(15,2);
@EndUserText.label: 'Devise" @Semantics.currencyCode: true Currency : abap.cuky;}Annotations importantes pour le popup :
| Annotation | Effet |
|---|---|
@EndUserText.label | Libellé du champ dans le popup |
@Consumption.valueHelpDefinition | Dropdown/Value Help |
@UI.multiLineText: true | Champ de texte multiligne |
@Semantics.amount.currencyCode | Champ de devise avec formatage |
Étape 2 : Behavior Definition
Associez l’action avec le paramètre :
managed implementation in class zbp_i_flightbooking unique;strict ( 2 );
define behavior for ZI_FlightBooking alias FlightBookingpersistent table zflight_booklock masterauthorization master ( instance ){ // CRUD standard create; update; delete;
// Action AVEC entité de paramètres action cancelBooking parameter ZA_CancelBookingParams result [1] $self;
// Action sans paramètre (pour comparaison) action confirmBooking result [1] $self;
// Validation pour l'annulation validation validateCancellation on save { field BookingStatus; }}Le mot-clé parameter fait en sorte que Fiori Elements génère automatiquement un dialogue.
Étape 3 : Implementation de l’action
Dans la Behavior Implementation Class, vous traitez les paramètres :
CLASS lhc_flightbooking DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS cancelBooking FOR MODIFY IMPORTING keys FOR ACTION FlightBooking~cancelBooking RESULT result.ENDCLASS.
CLASS lhc_flightbooking IMPLEMENTATION. METHOD cancelBooking. " Lire les données actuelles READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking FIELDS ( booking_id booking_status flight_price currency_code ) WITH CORRESPONDING #( keys ) RESULT DATA(bookings).
LOOP AT keys ASSIGNING FIELD-SYMBOL(<key>). " Récupérer la réservation du résultat READ TABLE bookings INTO DATA(booking) WITH KEY booking_id = <key>-booking_id.
IF sy-subrc <> 0. " Réservation non trouvée APPEND VALUE #( %tky = <key>-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'Réservation non trouvée' ) ) TO reported-flightbooking. APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking. CONTINUE. ENDIF.
" === Lire les paramètres du popup === DATA(cancel_reason) = <key>-%param-CancellationReason. DATA(remarks) = <key>-%param-Remarks. DATA(notify) = <key>-%param-NotifyCustomer. DATA(refund_amount) = <key>-%param-RefundAmount. DATA(currency) = <key>-%param-Currency.
" Validation : champ obligatoire raison de l'annulation IF cancel_reason IS INITIAL. APPEND VALUE #( %tky = <key>-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'La raison de l\'annulation est un champ obligatoire' ) ) TO reported-flightbooking. APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking. CONTINUE. ENDIF.
" Validation : le remboursement ne peut pas être supérieur au prix de la réservation IF refund_amount > booking-flight_price. APPEND VALUE #( %tky = <key>-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = |Le remboursement ne peut pas être supérieur à { booking-flight_price } { booking-currency_code }| ) ) TO reported-flightbooking. APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking. CONTINUE. ENDIF.
" Mettre le statut sur Annulé MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking UPDATE FIELDS ( booking_status cancellation_reason remarks ) WITH VALUE #( ( %tky = <key>-%tky booking_status = 'X' " Cancelled cancellation_reason = cancel_reason remarks = remarks ) ).
" Optionnel : Notifier le client IF notify = abap_true. send_cancellation_email( booking_id = booking-booking_id reason = cancel_reason remarks = remarks ). ENDIF.
" Optionnel : Traiter le remboursement IF refund_amount > 0. process_refund( booking_id = booking-booking_id amount = refund_amount currency = currency ). ENDIF. ENDLOOP.
" Retourner les données mises à jour READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(updated_bookings).
result = VALUE #( FOR bk IN updated_bookings ( %tky = bk-%tky %param = bk ) ).
" Message de succès APPEND VALUE #( %msg = new_message_with_text( severity = if_abap_behv_message=>severity-success text = |{ lines( updated_bookings ) } réservation(s) annulée(s)| ) ) TO reported-flightbooking. ENDMETHOD.ENDCLASS.Annotations UI pour la mise en page du popup
Affinez la mise en page du popup avec des annotations supplémentaires :
@EndUserText.label: 'Données d\'annulation"define abstract entity ZA_CancelBookingParams{ @EndUserText.label: 'Raison de l\'annulation" @UI.defaultValue: 'KA" @Consumption.valueHelpDefinition: [{ entity: { name: 'ZI_CancellationReasonVH', element: 'ReasonCode' }, useForValidation: true }] CancellationReason : abap.char(2);
@EndUserText.label: 'Remarque" @UI.multiLineText: true @UI.placeholder: 'Optionnel : Informations supplémentaires sur l\'annulation" Remarks : abap.string(500);
@EndUserText.label: 'Notifier le client" @UI.defaultValue: 'true" NotifyCustomer : abap_boolean;
@EndUserText.label: 'Montant du remboursement" @Semantics.amount.currencyCode: 'Currency" @UI.defaultValue: '0.00" RefundAmount : abap.curr(15,2);
@EndUserText.label: 'Devise" @Semantics.currencyCode: true @UI.defaultValue: 'EUR" @Consumption.valueHelpDefinition: [{ entity: { name: 'I_Currency', element: 'Currency' } }] Currency : abap.cuky;}Annotations UI importantes
| Annotation | Effet | Exemple |
|---|---|---|
@UI.defaultValue | Valeur pré-remplie | 'EUR' |
@UI.placeholder | Texte d’espace réservé | 'Saisir une remarque...' |
@UI.multiLineText | Champ de saisie multiligne | Pour les textes longs |
@UI.hidden | Masquer le champ | Champs techniques |
@Consumption.valueHelpDefinition | Value Help/Dropdown | Champs de sélection |
Différents types de champs dans le popup
Dropdown avec Value Help
@EndUserText.label: 'Priorité"@Consumption.valueHelpDefinition: [{ entity: { name: 'ZI_PriorityVH', element: 'Priority' }}]Priority : abap.char(1);Champ de date
@EndUserText.label: 'Nouvelle date de vol"@UI.defaultValue: '#(TODAY)"NewFlightDate : abap.dats;Checkbox
@EndUserText.label: 'Envoyer une confirmation par e-mail"@UI.defaultValue: 'false"SendConfirmation : abap_boolean;Texte multiligne
@EndUserText.label: 'Justification"@UI.multiLineText: trueJustification : abap.string(1000);Montant en devise
@EndUserText.label: 'Montant"@Semantics.amount.currencyCode: 'Currency"Amount : abap.curr(15,2);
@EndUserText.label: 'Devise"@Semantics.currencyCode: trueCurrency : abap.cuky;Champ de quantité
@EndUserText.label: 'Quantité"@Semantics.quantity.unitOfMeasure: 'Unit"Quantity : abap.quan(13,3);
@EndUserText.label: 'Unité"@Semantics.unitOfMeasure: trueUnit : abap.unit(3);Exemple complet de réservation de vol
Voici un exemple complet de bout en bout pour une action de transfert :
Abstract Entity : Paramètres de transfert
@EndUserText.label: 'Paramètres de transfert"define abstract entity ZA_RescheduleParams{ @EndUserText.label: 'Nouvelle date de vol" NewFlightDate : abap.dats;
@EndUserText.label: 'Nouveau numéro de vol" @Consumption.valueHelpDefinition: [{ entity: { name: 'ZI_FlightConnectionVH', element: 'FlightId' } }] NewFlightId : abap.numc(4);
@EndUserText.label: 'Accepter la différence de prix" AcceptPriceDiff : abap_boolean;
@EndUserText.label: 'Remarque" @UI.multiLineText: true Remarks : abap.string(500);}Behavior Definition
define behavior for ZI_FlightBooking alias FlightBooking{ action rescheduleBooking parameter ZA_RescheduleParams result [1] $self;}Projection Behavior
projection implementation in class zbp_c_flightbooking unique;
define behavior for ZC_FlightBooking alias FlightBooking{ use action rescheduleBooking;}Implementation
METHOD rescheduleBooking. " Lire les réservations actuelles READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(bookings).
LOOP AT keys ASSIGNING FIELD-SYMBOL(<key>). READ TABLE bookings INTO DATA(booking) WITH KEY booking_id = <key>-booking_id.
" === Paramètres du popup === DATA(new_date) = <key>-%param-NewFlightDate. DATA(new_flight) = <key>-%param-NewFlightId. DATA(accept_diff) = <key>-%param-AcceptPriceDiff. DATA(remarks) = <key>-%param-Remarks.
" Validation : date dans le futur IF new_date < cl_abap_context_info=>get_system_date( ). APPEND VALUE #( %tky = <key>-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'La date de vol doit être dans le futur' ) ) TO reported-flightbooking. APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking. CONTINUE. ENDIF.
" Calculer la différence de prix DATA(new_price) = get_flight_price( new_flight ). DATA(price_diff) = new_price - booking-flight_price.
" Augmentation de prix sans acceptation = erreur IF price_diff > 0 AND accept_diff = abap_false. APPEND VALUE #( %tky = <key>-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = |Différence de prix de { price_diff } { booking-currency_code } doit être acceptée| ) ) TO reported-flightbooking. APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking. CONTINUE. ENDIF.
" Effectuer le transfert MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking UPDATE FIELDS ( flight_date flight_id flight_price remarks ) WITH VALUE #( ( %tky = <key>-%tky flight_date = new_date flight_id = new_flight flight_price = new_price remarks = remarks ) ). ENDLOOP.
" Retourner le résultat READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(updated).
result = VALUE #( FOR bk IN updated ( %tky = bk-%tky %param = bk ) ).
" Message de succès APPEND VALUE #( %msg = new_message_with_text( severity = if_abap_behv_message=>severity-success text = |{ lines( updated ) } réservation(s) transférée(s)| ) ) TO reported-flightbooking.ENDMETHOD.Intégration UI dans CDS View
@EndUserText.label: 'Réservation de vol"define view entity ZC_FlightBooking as projection on ZI_FlightBooking{ @UI.lineItem: [ { position: 10 }, { type: #FOR_ACTION, dataAction: 'cancelBooking', label: 'Annuler', criticality: #NEGATIVE }, { type: #FOR_ACTION, dataAction: 'rescheduleBooking', label: 'Transférer' } ] @UI.identification: [ { position: 10 }, { type: #FOR_ACTION, dataAction: 'rescheduleBooking', label: 'Transférer' } ] key BookingId,
// autres champs...}Validation des saisies popup
Dans le code de l’action (recommandé)
" Vérifier le champ obligatoireIF <key>-%param-CancellationReason IS INITIAL. APPEND VALUE #( %tky = <key>-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'La raison de l\'annulation est requise' ) ) TO reported-flightbooking. APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking. RETURN.ENDIF.Avec Validation dans le Behavior
define behavior for ZI_FlightBooking{ action cancelBooking parameter ZA_CancelBookingParams result [1] $self;
" La validation est exécutée après l'action validation validateAfterCancel on save { field booking_status; }}Best Practices pour les actions popup
1. Identifier les champs obligatoires
@EndUserText.label: 'Raison *' " Astérisque dans le label@ObjectModel.mandatory: true " Champ obligatoireReason : abap.char(2);2. Valeurs par défaut judicieuses
@UI.defaultValue: 'EUR' " Pour la devise@UI.defaultValue: 'true' " Pour la checkbox@UI.defaultValue: '#(TODAY)' " Pour la date3. Value Helps pour les champs de sélection
@Consumption.valueHelpDefinition: [{ entity: { name: 'ZI_ReasonVH', element: 'Code' }, useForValidation: true}]4. Messages d’erreur clairs
" ❌ Mauvaistext = 'Erreur de saisie"
" ✅ Bontext = |Le remboursement ({ refund_amount } { currency }) ne peut pas être supérieur au prix de la réservation ({ booking-flight_price } { booking-currency_code })|5. Limiter la taille du popup
Maximum 5-6 champs par popup. Pour des saisies plus complexes : utiliser un wizard ou une page séparée.
Popup vs. Édition en ligne
| Scénario | Recommandation |
|---|---|
| 1-2 valeurs supplémentaires | Action popup |
| Formulaires complexes | Page d’objet séparée |
| Modification en masse | Édition en ligne ou application dédiée |
| Confirmation sans saisie | Action sans paramètre |
Résumé
Les actions popup dans RAP permettent des saisies utilisateur interactives avant l’exécution :
| Composant | Tâche |
|---|---|
| Abstract Entity | Définit les champs et types de données du popup |
| Behavior Definition | Lie l’action avec parameter |
| Implementation | Lit %param et traite les valeurs |
| Annotations UI | Contrôle l’apparence et le comportement |
Avec quelques annotations et une structure claire, vous créez des dialogues conviviaux qui s’intègrent parfaitement dans Fiori Elements.
Articles complémentaires : RAP Actions et Functions pour les bases des actions, RAP Nachrichten pour la gestion des erreurs, RAP CDS Pattern pour une architecture simplifiée et CDS Annotations pour plus de possibilités d’annotations.