[ABAP] SALV-Grid: Eventhandler für Doppelklick auf eine Zelle (double_click)

CLASS lcl_salv DEFINITION FINAL.

  PUBLIC SECTION.

    TYPES: BEGIN OF ty_mara_makt,
             matnr TYPE mara-matnr,
             laeda TYPE mara-laeda,
             mtart TYPE mara-mtart,
             meins TYPE mara-meins,
             maktx TYPE makt-maktx,
           END OF ty_mara_makt.

    CLASS-DATA: o_salv TYPE REF TO cl_salv_table.
    CLASS-DATA: it_mara TYPE STANDARD TABLE OF ty_mara_makt WITH DEFAULT KEY.

    CLASS-METHODS on_double_click FOR EVENT double_click OF cl_salv_events_table
      IMPORTING
        row
        column
        sender.
ENDCLASS.

CLASS lcl_salv IMPLEMENTATION.

  METHOD on_double_click.
    IF o_salv IS BOUND.
* Wenn Spalte 'MATNR'
      IF column EQ 'MATNR'.
* Wert in der geklickten Zelle holen
        DATA(lv_matnr18) = CONV matnr18( o_salv->get_selections( )->get_current_cell( )-value ).

* aufgrund Änderungen im SALV-Klassenmodell ist bei bestimmten SP
* der Aufruf von get_current_cell( )-value leer,
* also, hier nochmal auf die "alte" Art die geklickten Zelldaten holen
        IF lv_matnr18 IS INITIAL.
          lv_matnr18 = it_mara[ row ]-matnr.
        ENDIF.

        IF NOT lv_matnr18 IS INITIAL.
* Parameter zum Aufruf MM03:
* https://www.samplecodeabap.com/call-transaction-mm03-with-specific-tab/

* MATNR setzen
          SET PARAMETER ID 'MAT' FIELD lv_matnr18.
* K - Grunddaten anzeigen
          SET PARAMETER ID 'MXX' FIELD 'K'.
* Transaktion MM03 aufrufen (Material anzeigen)
          CALL TRANSACTION 'MM03' AND SKIP FIRST SCREEN.
        ENDIF.
      ENDIF.
    ENDIF.
  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

  SELECT FROM mara AS m
    INNER JOIN makt AS t ON m~matnr = t~matnr
    FIELDS m~matnr,
           m~laeda,
           m~mtart,
           m~meins,
           t~maktx
    WHERE t~spras EQ @sy-langu
    INTO TABLE @lcl_salv=>it_mara
    UP TO 50 ROWS.

  IF sy-subrc = 0.
    TRY.
        cl_salv_table=>factory( IMPORTING r_salv_table = lcl_salv=>o_salv
                                CHANGING  t_table      = lcl_salv=>it_mara ).

* Grundeinstellungen
        lcl_salv=>o_salv->get_functions( )->set_all( abap_true ).
        lcl_salv=>o_salv->get_columns( )->set_optimize( abap_true ).
        lcl_salv=>o_salv->get_display_settings( )->set_list_header( 'Material' ).
        lcl_salv=>o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
        lcl_salv=>o_salv->get_selections( )->set_selection_mode( if_salv_c_selection_mode=>row_column ).

* Spaltenüberschriften: technischer Name und Beschreibungstexte, Short Text und Medium Text leer lassen für Autosize
        LOOP AT lcl_salv=>o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
          DATA(o_col) = <c>-r_column.
          o_col->set_short_text( || ).
          o_col->set_medium_text( || ).
          o_col->set_long_text( |{ o_col->get_long_text( ) }| ).
        ENDLOOP.

* Event-Hanlder für Link-Klick
        SET HANDLER lcl_salv=>on_double_click FOR lcl_salv=>o_salv->get_event( ).

        lcl_salv=>o_salv->display( ).

      CATCH cx_root INTO DATA(e_txt).
        WRITE: / e_txt->get_text( ).
    ENDTRY.
  ENDIF.

Links

[ABAP] SALV-Grid: Eventhandler für Klick auf eine Zelle (link_click, hotspot)

CLASS lcl_salv DEFINITION FINAL.

  PUBLIC SECTION.

    TYPES: BEGIN OF ty_mara_makt,
             matnr TYPE mara-matnr,
             laeda TYPE mara-laeda,
             mtart TYPE mara-mtart,
             meins TYPE mara-meins,
             maktx TYPE makt-maktx,
           END OF ty_mara_makt.

    CLASS-DATA: o_salv TYPE REF TO cl_salv_table.
    CLASS-DATA: it_mara TYPE STANDARD TABLE OF ty_mara_makt WITH DEFAULT KEY.

    CLASS-METHODS on_link_click FOR EVENT link_click OF cl_salv_events_table
      IMPORTING
        row
        column
        sender.
ENDCLASS.

CLASS lcl_salv IMPLEMENTATION.

  METHOD on_link_click.
    IF o_salv IS BOUND.
* Wenn Spalte 'MATNR'
      IF column EQ 'MATNR'.
* Wert in der geklickten Zelle holen
        DATA(lv_matnr18) = CONV matnr18( o_salv->get_selections( )->get_current_cell( )-value ).

* aufgrund Änderungen im SALV-Klassenmodell ist bei bestimmten SP
* der Aufruf von get_current_cell( )-value leer,
* also, hier nochmal auf die "alte" Art die geklickten Zelldaten holen
        IF lv_matnr18 IS INITIAL.
          lv_matnr18 = it_mara[ row ]-matnr.
        ENDIF.

        IF NOT lv_matnr18 IS INITIAL.
* Parameter zum Aufruf MM03:
* https://www.samplecodeabap.com/call-transaction-mm03-with-specific-tab/

* MATNR setzen
          SET PARAMETER ID 'MAT' FIELD lv_matnr18.
* K - Grunddaten anzeigen
          SET PARAMETER ID 'MXX' FIELD 'K'.
* Transaktion MM03 aufrufen (Material anzeigen)
          CALL TRANSACTION 'MM03' AND SKIP FIRST SCREEN.
        ENDIF.
      ENDIF.
    ENDIF.
  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

  SELECT FROM mara AS m
    INNER JOIN makt AS t ON m~matnr = t~matnr
    FIELDS m~matnr,
           m~laeda,
           m~mtart,
           m~meins,
           t~maktx
    WHERE t~spras EQ @sy-langu
    INTO TABLE @lcl_salv=>it_mara
    UP TO 50 ROWS.

  IF sy-subrc = 0.
    TRY.
        cl_salv_table=>factory( IMPORTING r_salv_table = lcl_salv=>o_salv
                                CHANGING  t_table      = lcl_salv=>it_mara ).

* Grundeinstellungen
        lcl_salv=>o_salv->get_functions( )->set_all( abap_true ).
        lcl_salv=>o_salv->get_columns( )->set_optimize( abap_true ).
        lcl_salv=>o_salv->get_display_settings( )->set_list_header( 'Material' ).
        lcl_salv=>o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
        lcl_salv=>o_salv->get_selections( )->set_selection_mode( if_salv_c_selection_mode=>row_column ).

* Spaltenüberschriften: technischer Name und Beschreibungstexte, Short Text und Medium Text leer lassen für Autosize
        LOOP AT lcl_salv=>o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
          DATA(o_col) = <c>-r_column.
          o_col->set_short_text( || ).
          o_col->set_medium_text( || ).
          o_col->set_long_text( |{ o_col->get_long_text( ) }| ).
        ENDLOOP.

* Link-Klick für Spalte MATNR
        CAST cl_salv_column_table( lcl_salv=>o_salv->get_columns( )->get_column( 'MATNR' ) )->set_cell_type( if_salv_c_cell_type=>hotspot ).

* Event-Hanlder für Link-Klick
        SET HANDLER lcl_salv=>on_link_click FOR lcl_salv=>o_salv->get_event( ).

        lcl_salv=>o_salv->display( ).

      CATCH cx_root INTO DATA(e_txt).
        WRITE: / e_txt->get_text( ).
    ENDTRY.
  ENDIF.

[ABAP] Editierbares SALV-Grid (IF_SALV_GUI_OM_EXTEND_GRID_API, IF_SALV_GUI_OM_EDIT_RESTRICTED) mit Edit-Buttons

* Quelle: https://blogs.sap.com/2022/08/01/editable-cl_salv_table-after-release-756/
* ab SAP Release 756
* Achtung: das Ganze funktioniert nur für kleine Tabellen mit max. 5000 Zellen, siehe:
*
* Methode: CL_SALV_GUI_OM_ADAPTER_TABLE->CAN_RUN_RESTRICTED_EDIT_MODE( )
* Konstante: CV_MAX_CELLS_FOR_EDITABLE (Wert: 5000).

* ab SAP Release 758
* Methode: CL_SALV_GUI_OM_EDITABLE_HNDLR->REQUEST_DATA_SET_OF_SIZE( )
* Variable: MAX_CELLS_FOR_EDITABLE = 10000 (medium, auch standardmäßig im Constructor gesetzt) oder 100000 (large)

* Eventhandler
CLASS lcl_salv DEFINITION.
  PUBLIC SECTION.
* Bezeichner der Buttons
    CONSTANTS: co_btn_edit TYPE string VALUE 'BTN_EDIT'.
    CONSTANTS: co_btn_save TYPE string VALUE 'BTN_SAVE'.

* Platzhalter für Referenz auf SALV-Grid
    CLASS-DATA: o_salv TYPE REF TO cl_salv_table.
    CLASS-DATA: it_equi TYPE STANDARD TABLE OF equi WITH DEFAULT KEY.

* Eventhandler-Methode für Button-Klicks in der Toolbar des SALV-Grids
    CLASS-METHODS: on_toolbar_click FOR EVENT added_function OF cl_salv_events_table
      IMPORTING
        e_salv_function
        sender.
  PRIVATE SECTION.
* Edit-Status des SALV-Grids
    CLASS-DATA: gv_edit TYPE abap_bool VALUE abap_false.
ENDCLASS.

CLASS lcl_salv IMPLEMENTATION.
  METHOD on_toolbar_click.
    TRY.
        IF o_salv IS BOUND.
* extended Grid API holen		
          DATA(o_api) = o_salv->extended_grid_api( ).
          DATA(o_edit) = o_api->editable_restricted( ).

          CASE e_salv_function.

            WHEN co_btn_edit.
* Edit-Modus umschalten
              IF gv_edit = abap_false.
                gv_edit = abap_true.
              ELSE.
                gv_edit = abap_false.
              ENDIF.

* alle Spalte(n) (nicht) editierbar setzen
*              DATA(o_typedescr) = cl_abap_tabledescr=>describe_by_data( p_data = it_equi ).
*              DATA(o_tabledescr) = CAST cl_abap_tabledescr( o_typedescr ).
*              DATA(o_structdescr) = CAST cl_abap_structdescr( o_tabledescr->get_table_line_type( ) ).

*              LOOP AT o_structdescr->get_components( ) ASSIGNING FIELD-SYMBOL(<c>).

*                o_edit->set_attributes_for_columnname( EXPORTING columnname              = CONV #( <c>-name )
*                                                                 all_cells_input_enabled = gv_edit ).

*              ENDLOOP.

* einzelne Spalte(n) (nicht) editierbar setzen
              o_edit->set_attributes_for_columnname( EXPORTING columnname              = 'ERNAM'
                                                               all_cells_input_enabled = gv_edit ).

              o_edit->set_attributes_for_columnname( EXPORTING columnname              = 'EQTYP'
                                                               all_cells_input_enabled = gv_edit ).

              o_edit->validate_changed_data( ).
              o_salv->refresh( ).

            WHEN co_btn_save.
* Daten auf Validität prüfen
              DATA(lv_data_is_valid) = abap_false.

* Verification of Changes and Triggering of Event DATA_CHANGED
              o_edit->validate_changed_data( IMPORTING is_input_data_valid = lv_data_is_valid ).
              o_salv->refresh( ).

              IF lv_data_is_valid = abap_true.
* Daten hier speichern / weiterverarbeiten
                MESSAGE co_btn_save TYPE 'I'.
              ENDIF.
          ENDCASE.
        ENDIF.

      CATCH cx_root INTO DATA(e_txt).
        MESSAGE e_txt->get_text( ) TYPE 'I'.
    ENDTRY.

  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  TRY.
* Beispieldaten (Equipment) holen
      SELECT FROM equi
        FIELDS *
        INTO TABLE @lcl_salv=>it_equi
        UP TO 100 ROWS.

      IF sy-subrc = 0.
        cl_salv_table=>factory( EXPORTING r_container  = cl_gui_container=>default_screen
                                IMPORTING r_salv_table = lcl_salv=>o_salv
                                CHANGING  t_table      = lcl_salv=>it_equi ).

* Standardbuttons der SALV-Table einblenden
        lcl_salv=>o_salv->get_functions( )->set_all( abap_true ).

* SALV-Table vorbereiten auf großen, editierbaren Datensatz
        DATA(o_api) = lcl_salv=>o_salv->extended_grid_api( ).
        DATA(o_edit) = o_api->editable_restricted( ).
* medium = 10000 Zellen (Standard), large = 100000 Zellen
        o_edit->request_data_set_of_size( size = if_salv_gui_om_edit_restricted=>large ).
* Toolbar-Buttons für Edit-Mode aktivieren, Standardbuttons müssen eingeblendet sein (get_functions( )->set_all( abap_true ))
        o_edit->activate_toolbar_edit_buttons( EXPORTING local_edit_group = abap_true ).

* Eigenen SALV-Button hinzufügen
* das Hinzufügen des Buttons funktioniert nur, wenn die SALV-Table innerhalb eines Containers (z.B. cl_gui_container=>default_screen) eingebettet ist
        lcl_salv=>o_salv->get_functions( )->add_function( name = |{ lcl_salv=>co_btn_edit }|
                                                          icon = |{ icon_edit_file }|
                                                          text = 'Edit'
                                                          tooltip = 'Daten editieren'
                                                          position = if_salv_c_function_position=>right_of_salv_functions ).

        lcl_salv=>o_salv->get_functions( )->add_function( name = |{ lcl_salv=>co_btn_save }|
                                                          icon = |{ icon_save_as_template }|
                                                          text = 'Save'
                                                          tooltip = 'Daten speichern'
                                                          position = if_salv_c_function_position=>right_of_salv_functions ).

* Eventhandler für Klicks in die Toolbar des SALV-Grids setzen
        SET HANDLER lcl_salv=>on_toolbar_click FOR lcl_salv=>o_salv->get_event( ).

* SALV anzeigen
        lcl_salv=>o_salv->display( ).

* Toolbar der Listausgabe unterdrücken
        cl_abap_list_layout=>suppress_toolbar( ).

* Listausgabe erzwingen für Erzeugung von cl_gui_container=>default_screen
        WRITE: space.

      ENDIF.
    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] SALV-Table: Eigenen Button einfügen und Ereignis abfangen

* http://ajanzen.com/pdf_dokumente/sap_abap/alv/alv_sel_mode_own_funct.pdf

* Eventhandler für neuen Button
CLASS lcl_events DEFINITION.
  PUBLIC SECTION.
* Bezeichner des Buttons
    CONSTANTS: co_btn_xl_export TYPE string VALUE 'BTN_XL_EXPORT'.

    CLASS-METHODS : on_toolbar_click FOR EVENT added_function OF cl_salv_events_table
      IMPORTING
          e_salv_function
          sender.
ENDCLASS.

CLASS lcl_events IMPLEMENTATION.
  METHOD on_toolbar_click.
    CASE e_salv_function.
      WHEN co_btn_xl_export.
        MESSAGE co_btn_xl_export TYPE 'S'.
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

* Toolbar der Listausgabe unterdrücken
  cl_abap_list_layout=>suppress_toolbar( ).

  DATA: o_alv TYPE REF TO cl_salv_table.
  DATA: it_tab TYPE ...

  cl_salv_table=>factory( EXPORTING
                            r_container = cl_gui_container=>default_screen
                          IMPORTING
                            r_salv_table = o_alv
                          CHANGING
                            t_table = it_tab ).

* Standardbuttons der SALV-Table ausblenden
  o_alv->get_functions( )->set_all( abap_false ).

* Eigenen SALV-Button hinzufügen
* das Hinzufügen des Buttons funktioniert nur, wenn die SALV-Table innerhalb eines Containers (z.B. cl_gui_container=>default_screen) eingebettet ist
  o_alv->get_functions( )->add_function( name = |{ lcl_events=>co_btn_xl_export }|
                                         icon = |{ icon_export }|
                                         text = 'Export'
                                         tooltip = 'Daten exportieren'
                                         position = if_salv_c_function_position=>right_of_salv_functions ).

* Eventhandler für Klicks in die Toolbar des SALV-Grids setzen
  SET HANDLER lcl_events=>on_toolbar_click FOR o_alv->get_event( ).

* SALV anzeigen
  o_alv->display( ).

* Listausgabe erzwingen für Erzeugung von cl_gui_container=>default_screen
  WRITE: space.

[ABAP] SALV-Table Eventhandling

* mögliche Events sind:
* SET HANDLER gr_events->on_user_command FOR o_alv->get_event( ).
* SET HANDLER gr_events->on_before_user_command FOR o_alv->get_event( ).
* SET HANDLER gr_events->on_after_user_command FOR o_alv->get_event( ).
* SET HANDLER gr_events->on_double_click FOR o_alv->get_event( ).
* SET HANDLER gr_events->on_top_of_page FOR o_alv->get_event( ).
* SET HANDLER gr_events->on_end_of_page FOR o_alv->get_event( ).
 
* Klasse für Eventhandling definieren
CLASS lcl_events DEFINITION.
  PUBLIC SECTION.
* Doppelklick
    CLASS-METHODS: on_double_click FOR EVENT double_click OF cl_salv_events_table
      IMPORTING
          row
          column
          sender.
* Link-Klick
    CLASS-METHODS: on_link_click FOR EVENT link_click OF cl_salv_events_table
      IMPORTING
          row
          column
          sender.
ENDCLASS.
 
CLASS lcl_events IMPLEMENTATION.
  METHOD on_double_click.
    MESSAGE | { row } , { column } | TYPE 'I'.
  ENDMETHOD.
  METHOD on_link_click.
    MESSAGE | { row } , { column } | TYPE 'I'.
  ENDMETHOD.
ENDCLASS.
 
DATA: o_salv TYPE REF TO cl_salv_table.

...
 
* Handler registrieren
SET HANDLER lcl_events=>on_double_click FOR o_salv->get_event( ).
SET HANDLER lcl_events=>on_link_click FOR o_salv->get_event( ).