Actions in RAP — Static, Instance, and Factory Actions
Learn to implement RAP actions for custom business operations like approving orders, copying records, and triggering workflows.
Actions — Static, Instance, and Factory Actions
What You'll Learn
- What actions are and the three types
- Instance actions: operations on a specific record
- Static actions: operations without selecting a record
- Factory actions: creating new records from existing ones
- Action parameters and result types
What Are Actions?
Actions are custom operations beyond standard CRUD. They appear as buttons in the Fiori UI. TechMart needs:
- Approve Order — change status from New to Approved (instance action)
- Create with Reference — copy an existing order (factory action)
- Generate Daily Report — runs without selecting an order (static action)
Instance Action — Approve Order
An instance action operates on a selected record.
Step 1: Declare in behavior definition
define behavior for ZI_TM_SalesOrder alias SalesOrder
{
...
action approve result [1] $self;
}
result [1] $self means the action returns the updated instance.
Step 2: Implement
METHOD approve.
" Read current status
READ ENTITIES OF ZI_TM_SalesOrder IN LOCAL MODE
ENTITY SalesOrder
FIELDS ( Status OrderId )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
LOOP AT lt_orders INTO DATA(ls_order).
" Only New orders can be approved
IF ls_order-Status <> 'N'.
APPEND VALUE #( %tky = ls_order-%tky ) TO failed-salesorder.
APPEND VALUE #( %tky = ls_order-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Order { ls_order-OrderId } cannot be approved (status is not New)| )
) TO reported-salesorder.
CONTINUE.
ENDIF.
" Update status to Approved
MODIFY ENTITIES OF ZI_TM_SalesOrder IN LOCAL MODE
ENTITY SalesOrder
UPDATE FIELDS ( Status )
WITH VALUE #( (
%tky = ls_order-%tky
Status = 'A'
) )
REPORTED DATA(ls_rep).
ENDLOOP.
" Return updated instances
READ ENTITIES OF ZI_TM_SalesOrder IN LOCAL MODE
ENTITY SalesOrder
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(lt_result).
result = VALUE #( FOR ls_r IN lt_result (
%tky = ls_r-%tky %param = ls_r ) ).
ENDMETHOD.
Static Action — No Instance Selection
A static action doesn't need a selected record.
define behavior for ZI_TM_SalesOrder alias SalesOrder
{
...
static action generateReport;
}
METHOD generateReport.
" Business logic that doesn't depend on a specific order
" For example: generate a daily summary, trigger batch processing
APPEND VALUE #(
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-success
text = |Daily report generation started| )
) TO reported-salesorder.
ENDMETHOD.
Factory Action — Create from Existing
A factory action creates a new instance, often by copying an existing one.
define behavior for ZI_TM_SalesOrder alias SalesOrder
{
...
factory action copyOrder [1];
}
METHOD copyOrder.
" Read the source order
READ ENTITIES OF ZI_TM_SalesOrder IN LOCAL MODE
ENTITY SalesOrder
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(lt_source).
DATA(ls_source) = lt_source[ 1 ].
" Create a copy with New status and today's date
MODIFY ENTITIES OF ZI_TM_SalesOrder IN LOCAL MODE
ENTITY SalesOrder
CREATE FIELDS ( CustomerId OrderDate Status Currency )
WITH VALUE #( (
%cid = 'copy_1'
CustomerId = ls_source-CustomerId
OrderDate = cl_abap_context_info=>get_system_date( )
Status = 'N'
Currency = ls_source-Currency
) )
MAPPED DATA(ls_mapped).
" Return the new instance
mapped-salesorder = ls_mapped-salesorder.
ENDMETHOD.
Actions with Parameters
Actions can accept input. Define an abstract entity for the parameter:
@EndUserText.label: 'Rejection Reason'
DEFINE ABSTRACT ENTITY ZA_TM_RejectParams
{
Reason : abap.string(200);
}
Declare the action with the parameter:
action rejectOrder parameter ZA_TM_RejectParams result [1] $self;
Access the parameter in the implementation:
METHOD rejectOrder.
DATA(lv_reason) = keys[ 1 ]-%param-Reason.
" Store reason, update status to Rejected, etc.
ENDMETHOD.
Exposing Actions in the Projection
Actions declared at the interface level must be exposed in the projection:
projection;
define behavior for ZC_TM_SalesOrder alias SalesOrder
{
use action approve;
use action copyOrder;
use action rejectOrder;
use static action generateReport;
}
And add UI annotations to show the button:
@UI.lineItem: [{ type: #FOR_ACTION, dataAction: 'approve',
label: 'Approve', position: 10 }]
Common Mistakes
- Instance action on multiple selections — RAP actions receive a table of keys. Loop through all of them, don't just process
keys[ 1 ]. - Forgetting to return result — If the behavior definition says
result [1] $self, the method MUST populate theresultparameter. Otherwise the Fiori UI won't refresh. - Not exposing in projection — An action declared at the interface level but not exposed in the projection behavior won't appear in the Fiori app.
- Mixing action and validation logic — Actions should execute operations. Put data validation in validations, not in actions.
Key Takeaways
- Actions are custom operations beyond CRUD — they appear as buttons in Fiori.
- Instance actions operate on selected records. Static actions don't need selection. Factory actions create new records.
- Use abstract entities for action parameters (user input).
- Actions must be exposed in the projection behavior with
use action. - Add
@UI.lineItemannotations withtype: #FOR_ACTIONto display action buttons.
Next Lesson
TechMart's users want to save partial work and come back later. In Lesson 21, we'll implement draft handling — the auto-save mechanism that lets users edit without committing, resuming later where they left off.