Events enable loose coupling between objects in ABAP. An object (publisher) can trigger events without knowing who will react to them. Other objects (subscribers) register as handlers and are notified when events occur.
Basic Concept
- EVENTS: Declares an event in a class
- RAISE EVENT: Triggers the event (publisher)
- SET HANDLER: Registers a method as event handler (subscriber)
- FOR: Specifies which object the handler applies to
Syntax
Declare Event
CLASS <classname> DEFINITION. EVENTS: <eventname> [ EXPORTING VALUE(<parameter>) TYPE <type> ].ENDCLASS.Trigger Event
RAISE EVENT <eventname> [ EXPORTING <parameter> = <value> ].Register Handler
SET HANDLER <handler_object>-><methodname> FOR <sender_object>.
" For all instancesSET HANDLER <handler_object>-><methodname> FOR ALL INSTANCES.Examples
1. Simple Event
" Publisher class: Triggers eventsCLASS lcl_button DEFINITION. PUBLIC SECTION. EVENTS: clicked.
METHODS: click.ENDCLASS.
CLASS lcl_button IMPLEMENTATION. METHOD click. WRITE: / 'Button was clicked'. RAISE EVENT clicked. ENDMETHOD.ENDCLASS.
" Subscriber class: Reacts to eventsCLASS lcl_form DEFINITION. PUBLIC SECTION. METHODS: on_button_clicked FOR EVENT clicked OF lcl_button.ENDCLASS.
CLASS lcl_form IMPLEMENTATION. METHOD on_button_clicked. WRITE: / 'Form: Button click processed!'. ENDMETHOD.ENDCLASS.
" UsageDATA: lo_button TYPE REF TO lcl_button, lo_form TYPE REF TO lcl_form.
lo_button = NEW #( ).lo_form = NEW #( ).
" Register handlerSET HANDLER lo_form->on_button_clicked FOR lo_button.
" Trigger eventlo_button->click( ).
" Output:" Button was clicked" Form: Button click processed!2. Event with Parameters
CLASS lcl_order_processor DEFINITION. PUBLIC SECTION. " Event with export parameters EVENTS: order_completed EXPORTING VALUE(ev_order_id) TYPE i VALUE(ev_amount) TYPE p DECIMALS 2.
METHODS: process_order IMPORTING iv_order_id TYPE i iv_amount TYPE p.ENDCLASS.
CLASS lcl_order_processor IMPLEMENTATION. METHOD process_order. WRITE: / |Order { iv_order_id } processed.|.
" Trigger event with data RAISE EVENT order_completed EXPORTING ev_order_id = iv_order_id ev_amount = iv_amount. ENDMETHOD.ENDCLASS.
CLASS lcl_notification_service DEFINITION. PUBLIC SECTION. " Handler method with SENDER METHODS: on_order_completed FOR EVENT order_completed OF lcl_order_processor IMPORTING ev_order_id ev_amount sender.ENDCLASS.
CLASS lcl_notification_service IMPLEMENTATION. METHOD on_order_completed. WRITE: / |Notification: Order { ev_order_id }|. WRITE: / |Amount: { ev_amount } EUR|. " sender contains reference to the triggering object ENDMETHOD.ENDCLASS.
" UsageDATA: lo_processor TYPE REF TO lcl_order_processor, lo_notification TYPE REF TO lcl_notification_service.
lo_processor = NEW #( ).lo_notification = NEW #( ).
SET HANDLER lo_notification->on_order_completed FOR lo_processor.
lo_processor->process_order( iv_order_id = 1001 iv_amount = '250.00' ).
" Output:" Order 1001 processed." Notification: Order 1001" Amount: 250.00 EUR3. Multiple Handlers for One Event
CLASS lcl_logger DEFINITION. PUBLIC SECTION. METHODS: on_order_completed FOR EVENT order_completed OF lcl_order_processor IMPORTING ev_order_id ev_amount.ENDCLASS.
CLASS lcl_logger IMPLEMENTATION. METHOD on_order_completed. WRITE: / |LOG: Order { ev_order_id } - { ev_amount } EUR|. ENDMETHOD.ENDCLASS.
CLASS lcl_statistics DEFINITION. PUBLIC SECTION. DATA: mv_total_orders TYPE i, mv_total_amount TYPE p DECIMALS 2.
METHODS: on_order_completed FOR EVENT order_completed OF lcl_order_processor IMPORTING ev_order_id ev_amount.ENDCLASS.
CLASS lcl_statistics IMPLEMENTATION. METHOD on_order_completed. mv_total_orders = mv_total_orders + 1. mv_total_amount = mv_total_amount + ev_amount. WRITE: / |STATS: { mv_total_orders } orders, Total: { mv_total_amount }|. ENDMETHOD.ENDCLASS.
" Usage - Register multiple handlersDATA: lo_processor TYPE REF TO lcl_order_processor, lo_notify TYPE REF TO lcl_notification_service, lo_logger TYPE REF TO lcl_logger, lo_statistics TYPE REF TO lcl_statistics.
lo_processor = NEW #( ).lo_notify = NEW #( ).lo_logger = NEW #( ).lo_statistics = NEW #( ).
" Register all handlersSET HANDLER: lo_notify->on_order_completed FOR lo_processor, lo_logger->on_order_completed FOR lo_processor, lo_statistics->on_order_completed FOR lo_processor.
lo_processor->process_order( iv_order_id = 1001 iv_amount = '100.00' ).lo_processor->process_order( iv_order_id = 1002 iv_amount = '200.00' ).
" All handlers are called!4. FOR ALL INSTANCES
CLASS lcl_global_logger DEFINITION. PUBLIC SECTION. METHODS: on_any_order_completed FOR EVENT order_completed OF lcl_order_processor IMPORTING ev_order_id sender.ENDCLASS.
CLASS lcl_global_logger IMPLEMENTATION. METHOD on_any_order_completed. WRITE: / |Global Log: Order { ev_order_id } processed by Processor|. ENDMETHOD.ENDCLASS.
" UsageDATA: lo_processor1 TYPE REF TO lcl_order_processor, lo_processor2 TYPE REF TO lcl_order_processor, lo_global_log TYPE REF TO lcl_global_logger.
lo_processor1 = NEW #( ).lo_processor2 = NEW #( ).lo_global_log = NEW #( ).
" Handler for ALL instances of the classSET HANDLER lo_global_log->on_any_order_completed FOR ALL INSTANCES.
lo_processor1->process_order( iv_order_id = 1 iv_amount = 50 ).lo_processor2->process_order( iv_order_id = 2 iv_amount = 75 ).
" Both are logged!5. Deactivate Handler
" Remove handlerSET HANDLER lo_notify->on_order_completed FOR lo_processor ACTIVATION space.
" Or explicitly with abap_falseSET HANDLER lo_logger->on_order_completed FOR lo_processor ACTIVATION abap_false.
" Reactivate handlerSET HANDLER lo_logger->on_order_completed FOR lo_processor ACTIVATION abap_true.6. Static Events (CLASS-EVENTS)
CLASS lcl_application DEFINITION. PUBLIC SECTION. " Static event - belongs to class, not instance CLASS-EVENTS: application_started.
CLASS-METHODS: start.ENDCLASS.
CLASS lcl_application IMPLEMENTATION. METHOD start. WRITE: / 'Application starting...'. RAISE EVENT application_started. ENDMETHOD.ENDCLASS.
CLASS lcl_startup_handler DEFINITION. PUBLIC SECTION. " Handler for class event METHODS: on_app_started FOR EVENT application_started OF lcl_application.ENDCLASS.
CLASS lcl_startup_handler IMPLEMENTATION. METHOD on_app_started. WRITE: / 'Startup handler: Initialization running...'. ENDMETHOD.ENDCLASS.
" UsageDATA: lo_handler TYPE REF TO lcl_startup_handler.
lo_handler = NEW #( ).
" For class events: FOR lcl_application (not FOR instance)SET HANDLER lo_handler->on_app_started FOR lcl_application.
lcl_application=>start( ).7. Events in Interfaces
INTERFACE lif_observable. EVENTS: data_changed EXPORTING VALUE(ev_new_value) TYPE string.ENDINTERFACE.
CLASS lcl_model DEFINITION. PUBLIC SECTION. INTERFACES: lif_observable.
METHODS: set_value IMPORTING iv_value TYPE string.
PRIVATE SECTION. DATA: mv_value TYPE string.ENDCLASS.
CLASS lcl_model IMPLEMENTATION. METHOD set_value. mv_value = iv_value. " Trigger event from interface RAISE EVENT lif_observable~data_changed EXPORTING ev_new_value = mv_value. ENDMETHOD.ENDCLASS.
CLASS lcl_view DEFINITION. PUBLIC SECTION. " Handler for interface event METHODS: on_data_changed FOR EVENT data_changed OF lif_observable IMPORTING ev_new_value.ENDCLASS.
CLASS lcl_view IMPLEMENTATION. METHOD on_data_changed. WRITE: / |View updated: { ev_new_value }|. ENDMETHOD.ENDCLASS.
" UsageDATA: lo_model TYPE REF TO lcl_model, lo_view TYPE REF TO lcl_view.
lo_model = NEW #( ).lo_view = NEW #( ).
SET HANDLER lo_view->on_data_changed FOR lo_model.
lo_model->set_value( 'New value' )." Output: View updated: New value8. Complete Observer Pattern
" Subject InterfaceINTERFACE lif_subject. METHODS: attach IMPORTING io_observer TYPE REF TO lif_observer, detach IMPORTING io_observer TYPE REF TO lif_observer, notify.ENDINTERFACE.
" Observer InterfaceINTERFACE lif_observer. METHODS: update IMPORTING iv_state TYPE string.ENDINTERFACE.
" Concrete SubjectCLASS lcl_weather_station DEFINITION. PUBLIC SECTION. INTERFACES: lif_subject.
EVENTS: weather_changed EXPORTING VALUE(ev_weather) TYPE string.
METHODS: set_weather IMPORTING iv_weather TYPE string.
PRIVATE SECTION. DATA: mt_observers TYPE TABLE OF REF TO lif_observer, mv_weather TYPE string.ENDCLASS.
CLASS lcl_weather_station IMPLEMENTATION. METHOD lif_subject~attach. APPEND io_observer TO mt_observers. ENDMETHOD.
METHOD lif_subject~detach. DELETE mt_observers WHERE table_line = io_observer. ENDMETHOD.
METHOD lif_subject~notify. LOOP AT mt_observers INTO DATA(lo_observer). lo_observer->update( mv_weather ). ENDLOOP. ENDMETHOD.
METHOD set_weather. mv_weather = iv_weather. lif_subject~notify( ). RAISE EVENT weather_changed EXPORTING ev_weather = mv_weather. ENDMETHOD.ENDCLASS.
" Concrete ObserverCLASS lcl_phone_display DEFINITION. PUBLIC SECTION. INTERFACES: lif_observer.
METHODS: on_weather_changed FOR EVENT weather_changed OF lcl_weather_station IMPORTING ev_weather.ENDCLASS.
CLASS lcl_phone_display IMPLEMENTATION. METHOD lif_observer~update. WRITE: / |Phone Display: { iv_state }|. ENDMETHOD.
METHOD on_weather_changed. WRITE: / |Phone Event: { ev_weather }|. ENDMETHOD.ENDCLASS.
" UsageDATA: lo_station TYPE REF TO lcl_weather_station, lo_phone TYPE REF TO lcl_phone_display.
lo_station = NEW #( ).lo_phone = NEW #( ).
" Observer Patternlo_station->lif_subject~attach( lo_phone ).
" Or with eventsSET HANDLER lo_phone->on_weather_changed FOR lo_station.
lo_station->set_weather( 'Sunny, 25°C' ).9. SENDER Parameter
CLASS lcl_multi_button_handler DEFINITION. PUBLIC SECTION. METHODS: on_button_clicked FOR EVENT clicked OF lcl_button IMPORTING sender. " Reference to triggering objectENDCLASS.
CLASS lcl_multi_button_handler IMPLEMENTATION. METHOD on_button_clicked. " sender contains the reference to the clicked button DATA(lo_button) = sender. WRITE: / 'A button was clicked'.
" Type check and cast possible IF sender IS INSTANCE OF lcl_button. " Access button-specific methods ENDIF. ENDMETHOD.ENDCLASS.
" UsageDATA: lo_btn1 TYPE REF TO lcl_button, lo_btn2 TYPE REF TO lcl_button, lo_handler TYPE REF TO lcl_multi_button_handler.
lo_btn1 = NEW #( ).lo_btn2 = NEW #( ).lo_handler = NEW #( ).
SET HANDLER lo_handler->on_button_clicked FOR ALL INSTANCES.
lo_btn1->click( ). " sender = lo_btn1lo_btn2->click( ). " sender = lo_btn210. Practical Example: ALV Event Handling
CLASS lcl_alv_handler DEFINITION. PUBLIC SECTION. METHODS: on_double_click FOR EVENT double_click OF cl_salv_events_table IMPORTING row column.
METHODS: on_link_click FOR EVENT link_click OF cl_salv_events_table IMPORTING row column.ENDCLASS.
CLASS lcl_alv_handler IMPLEMENTATION. METHOD on_double_click. WRITE: / |Double click on row { row }, column { column }|. ENDMETHOD.
METHOD on_link_click. WRITE: / |Link clicked in row { row }, column { column }|. ENDMETHOD.ENDCLASS.
" Usage with SALVDATA: lo_alv TYPE REF TO cl_salv_table, lo_events TYPE REF TO cl_salv_events_table, lo_handler TYPE REF TO lcl_alv_handler.
TRY. cl_salv_table=>factory( IMPORTING r_salv_table = lo_alv CHANGING t_table = lt_data ).
" Get events lo_events = lo_alv->get_event( ).
" Register handlers lo_handler = NEW #( ). SET HANDLER: lo_handler->on_double_click FOR lo_events, lo_handler->on_link_click FOR lo_events.
lo_alv->display( ).
CATCH cx_salv_msg.ENDTRY.Event Types
| Type | Declaration | SET HANDLER FOR |
|---|---|---|
| Instance event | EVENTS | Specific instance |
| Class event | CLASS-EVENTS | Class itself |
| Interface event | EVENTS in Interface | Implementing class |
Important Notes / Best Practice
- Events enable loose coupling – publisher doesn’t know subscribers.
- SENDER contains the reference to the triggering object.
FOR ALL INSTANCESfor global handlers (logging, monitoring).- ACTIVATION space/abap_false to deactivate handlers.
- Events are synchronous – handlers execute immediately.
- CLASS-EVENTS for class-wide events without instance.
- Use
INTERFACEfor events with loose coupling. - Observer Pattern ideal for UI updates and notifications.
- Handler methods must have the correct signature (
FOR EVENT ... OF). - Be careful with circular event chains – can cause infinite loops.