RAP Side Effects: Automatic UI Updates

Category
RAP
Published
Author
Johannes

Side Effects in RAP define which UI elements should be updated when field values change or actions are executed. They ensure a reactive user interface without manual reloading.

Why Side Effects?

Side Effects answer questions like:

  • Which fields need to be updated when the price changes?
  • Which UI areas need to reload after an action?
  • How are calculated fields automatically updated?

Typical Use Cases

ScenarioTriggerAffected Fields
Price calculationQuantity, Unit PriceTotal Price
Date calculationStart or End DateDuration, Work Days
Currency conversionCurrencyAll Amount Fields
Status changeAction executionStatus, Availability

Side Effects in the Behavior Definition

Side Effects are defined declaratively in the 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;
// Side Effects Block
side effects
{
// Field-Level Side Effects
field BeginDate affects field Duration;
field EndDate affects field Duration;
// Action-Level Side Effects
action calculatePrice affects field TotalPrice, field Currency;
// Determination Side Effects
determine action Prepare affects field Status;
}
}

Field-Level Side Effects

Field-Level Side Effects define which fields are updated when a specific field changes.

Simple Field Side Effect

side effects
{
// When BeginDate changes, update Duration
field BeginDate affects field Duration;
// When EndDate changes, update Duration
field EndDate affects field Duration;
}

Multiple Trigger Fields

side effects
{
// Multiple fields trigger the same update
field ( BeginDate, EndDate ) affects field Duration;
// Price calculation on quantity or price change
field ( Quantity, UnitPrice ) affects field TotalPrice;
}

Multiple Affected Fields

side effects
{
// One trigger field affects multiple target fields
field Quantity affects field TotalPrice, field TaxAmount, field NetPrice;
// Currency change affects all amount fields
field CurrencyCode affects field TotalPrice, field TaxAmount, field Discount;
}

$self - The Entire Instance

With $self, the entire instance is marked as affected:

side effects
{
// Currency change: Reload all fields
field CurrencyCode affects $self;
// Customer change: Update entire instance
field CustomerId affects $self;
}

Action-Level Side Effects

Action-Level Side Effects define which fields are updated after an action.

define behavior for ZI_Travel alias Travel
{
// Define actions
action calculatePrice result [1] $self;
action applyDiscount result [1] $self;
action setStatus result [1] $self;
side effects
{
// After price calculation, update these fields
action calculatePrice affects field TotalPrice, field TaxAmount;
// After discount application
action applyDiscount affects field TotalPrice, field DiscountAmount;
// Status change affects Status field
action setStatus affects field Status;
}
}

Action with Complex Side Effects

side effects
{
// Action affects multiple areas
action recalculateAll affects
field TotalPrice,
field TaxAmount,
field NetPrice,
field Currency,
entity _Bookings; // Also associations
// Action affects entire entity
action copyFromTemplate affects $self;
}

Determination Side Effects

When Determinations are executed, Side Effects can inform the UI about calculated values.

Behavior Definition

define behavior for ZI_Travel alias Travel
{
// Determination for price calculation
determination calculateTotalPrice on modify { field Quantity; field UnitPrice; }
// Determination for status
determination setInitialStatus on modify { create; }
side effects
{
// When calculateTotalPrice executes on Quantity change
determine action calculateTotalPrice executed on field Quantity
affects field TotalPrice;
// When calculateTotalPrice executes on UnitPrice change
determine action calculateTotalPrice executed on field UnitPrice
affects field TotalPrice;
}
}

Complete Example with Determination

managed implementation in class zbp_i_travel unique;
strict ( 2 );
define behavior for ZI_Travel alias Travel
persistent table ztravel
{
create;
update;
delete;
// Determinations
determination calculateDuration on modify { field BeginDate; field EndDate; }
determination calculatePrice on modify { field Quantity; field UnitPrice; field CurrencyCode; }
side effects
{
// Duration calculation
determine action calculateDuration executed on field BeginDate
affects field Duration;
determine action calculateDuration executed on field EndDate
affects field Duration;
// Price calculation
determine action calculatePrice executed on field Quantity
affects field TotalPrice, field TaxAmount;
determine action calculatePrice executed on field UnitPrice
affects field TotalPrice, field TaxAmount;
determine action calculatePrice executed on field CurrencyCode
affects field TotalPrice, field TaxAmount, field Currency;
}
}

Determination Implementation

CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS calculateDuration FOR DETERMINE ON MODIFY
IMPORTING keys FOR Travel~calculateDuration.
METHODS calculatePrice FOR DETERMINE ON MODIFY
IMPORTING keys FOR Travel~calculatePrice.
ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD calculateDuration.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( BeginDate EndDate )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Duration )
WITH VALUE #( FOR ls_travel IN lt_travel
WHERE ( BeginDate IS NOT INITIAL AND EndDate IS NOT INITIAL )
( %tky = ls_travel-%tky
Duration = ls_travel-EndDate - ls_travel-BeginDate ) )
REPORTED reported.
ENDMETHOD.
METHOD calculatePrice.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Quantity UnitPrice CurrencyCode )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( TotalPrice TaxAmount Currency )
WITH VALUE #( FOR ls_travel IN lt_travel
LET lv_total = ls_travel-Quantity * ls_travel-UnitPrice
lv_tax = lv_total * '0.19'
IN
( %tky = ls_travel-%tky
TotalPrice = lv_total
TaxAmount = lv_tax
Currency = ls_travel-CurrencyCode ) )
REPORTED reported.
ENDMETHOD.
ENDCLASS.

Side Effects with Associations

Side Effects can also affect associations:

define behavior for ZI_Travel alias Travel
{
association _Bookings { create; }
side effects
{
// Changes to Bookings affect Travel
field _Bookings affects field TotalPrice, field BookingCount;
// Currency change in Travel affects all Bookings
field CurrencyCode affects entity _Bookings;
}
}
define behavior for ZI_Booking alias Booking
{
association _Travel;
side effects
{
// Price in Booking affects total price in Travel
field Price affects field _Travel.TotalPrice;
}
}

Hierarchical Side Effects

define behavior for ZI_Travel alias Travel
{
side effects
{
// Update all Bookings when currency changes
field CurrencyCode affects entity _Bookings, entity _Passengers;
// After Copy action, reload all child entities
action copyWithDetails affects $self, entity _Bookings, entity _Passengers;
}
}

Target Fields and $self

Single Target Fields

side effects
{
field Quantity affects field TotalPrice;
}

Multiple Target Fields

side effects
{
field Quantity affects field TotalPrice, field TaxAmount, field NetPrice;
}

Entire Entity ($self)

side effects
{
// On status change: Reload complete instance
field Status affects $self;
// On copy: Update everything
action copy affects $self;
}

Entity (Associations)

side effects
{
// Update child entities
field CurrencyCode affects entity _Bookings;
// Update parent entity
field BookingPrice affects entity _Travel;
}

Complete Example

managed implementation in class zbp_i_travel unique;
strict ( 2 );
define behavior for ZI_Travel alias Travel
persistent table ztravel
draft table zdraft_travel
lock master total etag LastChangedAt
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
// Fields
field ( readonly ) TravelId, CreatedBy, CreatedAt;
field ( mandatory ) CustomerId;
// Associations
association _Bookings { create; }
// Determinations
determination calculateDuration on modify { field BeginDate; field EndDate; }
determination calculateTotalPrice on modify { field _Bookings; }
determination setInitialStatus on modify { create; }
// Actions
action ( features: instance ) acceptTravel result [1] $self;
action recalculatePrice result [1] $self;
// Side Effects
side effects
{
// Field-Level
field BeginDate affects field Duration, field DaysUntilStart;
field EndDate affects field Duration;
field CustomerId affects field CustomerName, field CustomerRating;
// Currency affects all amount fields
field CurrencyCode affects
field TotalPrice,
field TaxAmount,
entity _Bookings;
// Determination Side Effects
determine action calculateDuration executed on field BeginDate
affects field Duration;
determine action calculateDuration executed on field EndDate
affects field Duration;
determine action calculateTotalPrice executed on field _Bookings
affects field TotalPrice, field BookingCount;
// Action Side Effects
action acceptTravel affects field Status, field ApprovedAt, field ApprovedBy;
action recalculatePrice affects field TotalPrice, field TaxAmount, entity _Bookings;
}
}
define behavior for ZI_Booking alias Booking
persistent table zbooking
draft table zdraft_booking
lock dependent by _Travel
authorization dependent by _Travel
etag master LastChangedAt
{
create;
update;
delete;
association _Travel;
side effects
{
// Price change in Booking updates Travel total
field Price affects field _Travel.TotalPrice;
}
}

Best Practices

  1. Minimal Side Effects: Define only the Side Effects that are truly needed - too many can impact performance

  2. Specific Fields Instead of $self: Use $self only when the entire entity is actually affected

  3. Determination + Side Effect: Combine Determinations with Side Effects for automatic calculations

  4. Bidirectional Associations: Pay attention to the correct direction of Side Effects in parent-child relationships

  5. Performance: Side Effects trigger UI requests - test performance in complex scenarios

  6. Consistency: Ensure Side Effect definitions match the actual logic

" CORRECT: Side Effect matches the Determination
determination calculateTotal on modify { field Quantity; field Price; }
side effects
{
determine action calculateTotal executed on field Quantity affects field TotalPrice;
determine action calculateTotal executed on field Price affects field TotalPrice;
}
" WRONG: Side Effect without corresponding calculation
side effects
{
field Quantity affects field TotalPrice; " Who calculates TotalPrice?
}