ABAP – How to Ensure BACK Button Returns to Selection Screen Instead of Ending Transaction

abapalvdynprosap-selection-screens

I want to use an ALV grid with a selection screen but without adding additional dynpros and PAI PBO Modules, like shown in this Example.

Everything works fine, but I can't go back from ALV to selection screen since the report gets terminated.

For my understanding,
I need to adapt this part of code.
If I don't call the function RS_SET_SELSCREEN_STATUS,
I can go back to selection screen, but the F8 button is showing during the ALV Screen.

* Drucktastenleiste: Button "Ausführen (F8)" entfernen
    DATA: it_exclude_btn TYPE STANDARD TABLE OF rsexfcode WITH DEFAULT KEY.
    it_exclude_btn = VALUE #( ( fcode = 'ONLI' ) ).
 
    CALL FUNCTION 'RS_SET_SELSCREEN_STATUS'
      EXPORTING
        p_status  = '%_00' " akt. Standard-PF-Status des Dypro 2000
      TABLES
        p_exclude = it_exclude_btn.
 
* leere SAP-Toolbar ausblenden
    cl_abap_list_layout=>suppress_toolbar( ).
 
* Focus auf ALV setzen
    cl_gui_alv_grid=>set_focus( control = o_alv ).
 
* Flag für Screen-Status auf ALV-Anzeige setzen
    gv_screen_status = 'IN_ALV'.
  ENDIF.

Please help me to make the Back Button work in ALV view.


EDIT:
You can test the behaviour using the code below:

**********************************************************************
*
* Variablen
*
**********************************************************************
DATA: gv_screen_status TYPE string VALUE 'INIT'.
DATA: gv_carrid   TYPE spfli-carrid.
DATA: gv_connid TYPE spfli-connid.
DATA: o_alv TYPE REF TO cl_gui_alv_grid.
DATA: it_spfli TYPE STANDARD TABLE OF spfli WITH DEFAULT KEY.
**********************************************************************
*
* leeres Dynpro als Dummy für ALV-Grid
*
**********************************************************************
SELECTION-SCREEN BEGIN OF SCREEN 2000.
SELECTION-SCREEN END OF SCREEN 2000.
**********************************************************************
*
* SELECTION-SCREEN
*
**********************************************************************
SELECT-OPTIONS: so_carr FOR gv_carrid.
SELECT-OPTIONS: so_conn FOR gv_connid.
**********************************************************************
*
* Eventhandler
*
**********************************************************************
CLASS lcl_events DEFINITION.
 
  PUBLIC SECTION.
 
    CLASS-METHODS:
      on_toolbar FOR EVENT toolbar OF cl_gui_alv_grid
        IMPORTING
            e_object
            e_interactive
            sender.
 
    CLASS-METHODS:
      on_user_command FOR EVENT user_command OF cl_gui_alv_grid
        IMPORTING
            e_ucomm
            sender.
 
    CLASS-METHODS:
      on_data_changed FOR EVENT data_changed OF cl_gui_alv_grid
        IMPORTING
            er_data_changed
            sender.
ENDCLASS.
 
CLASS lcl_events IMPLEMENTATION.
 
  METHOD on_data_changed.
* geänderte Zellen durchgehen
    LOOP AT er_data_changed->mt_good_cells ASSIGNING FIELD-SYMBOL(<c>).
      IF <c> IS ASSIGNED.
* Zeile x aus der iTab it_spfli rausholen und daraus die Zelle anhand des Spaltennamens (Feldnamens) holen
        ASSIGN COMPONENT <c>-fieldname OF STRUCTURE it_spfli[ <c>-row_id ] TO FIELD-SYMBOL(<f>).
 
        IF <f> IS ASSIGNED.
* Änderungswert in die Zelle der iTab (it_spfli) rückschreiben
          <f> = <c>-value.
        ENDIF.
      ENDIF.
 
    ENDLOOP.
 
* DB Update
    FIELD-SYMBOLS: <tab> TYPE table.
    FIELD-SYMBOLS: <row> TYPE spfli.
 
    ASSIGN er_data_changed->mp_mod_rows->* TO <tab>.
 
    LOOP AT <tab> ASSIGNING <row>.
* DB Update hier
    ENDLOOP.
 
  ENDMETHOD.
 
  METHOD on_user_command.
* wenn BTN_REFRESH geklickt
    IF e_ucomm = 'BTN_REFRESH'.
      IF o_alv IS BOUND.
        SELECT * FROM spfli INTO TABLE @it_spfli
          WHERE carrid IN @so_carr
            AND connid IN @so_conn.
 
        sender->refresh_table_display( is_stable = VALUE lvc_s_stbl( row = abap_true
                                                                     col = abap_true )
                                       i_soft_refresh = abap_false ).
      ENDIF.
    ENDIF.
  ENDMETHOD.
 
  METHOD on_toolbar.
* alle Buttons entfernen, bis auf folgende:
    DELETE e_object->mt_toolbar WHERE
        function NE cl_gui_alv_grid=>mc_fc_refresh          " Refresh
    AND function NE cl_gui_alv_grid=>mc_mb_export           " Excel
    AND function NE cl_gui_alv_grid=>mc_fc_current_variant. " Layout
 
    LOOP AT e_object->mt_toolbar ASSIGNING FIELD-SYMBOL(<fs_button>) WHERE ( function = cl_gui_alv_grid=>mc_fc_refresh ).
* neues USER-Command setzen, damit bei Button-Klick on_user_command getriggert wird
      <fs_button>-function = 'BTN_REFRESH'.
    ENDLOOP.
 
  ENDMETHOD.
ENDCLASS.
**********************************************************************
*
* INITIALIZATION
*
**********************************************************************
INITIALIZATION.
 
* Vorbelegungen für Selektionsbild
  so_carr[] = VALUE #( ( sign = 'I' option = 'EQ' low = 'LH' ) ).
 
**********************************************************************
*
* AT SELECTION-SCREEN OUTPUT
*
**********************************************************************
AT SELECTION-SCREEN OUTPUT.
 
* Wenn vorher das Selektionsbild 1000 angezeigt wurde
  IF gv_screen_status = 'IN_SELECTION'.
* Daten holen
    SELECT * FROM spfli INTO TABLE @it_spfli
       WHERE carrid IN @so_carr
         AND connid IN @so_conn.
* ALV-Gitter anzeigen
    o_alv = NEW #( i_parent      = cl_gui_container=>default_screen
                   i_appl_events = abap_true ).
 
* Eventhandler registrieren
    SET HANDLER lcl_events=>on_toolbar FOR o_alv.
    SET HANDLER lcl_events=>on_data_changed FOR o_alv.
    SET HANDLER lcl_events=>on_user_command FOR o_alv.
 
* Ereignisse registrieren
    o_alv->register_edit_event( i_event_id = cl_gui_alv_grid=>mc_evt_enter ).
    o_alv->register_edit_event( i_event_id = cl_gui_alv_grid=>mc_evt_modified ).
 
* ALV-Grid selektionsbereit setzen
    o_alv->set_ready_for_input( i_ready_for_input = 1 ).
 
* Layout des ALV setzen
    DATA(lv_layout) = VALUE lvc_s_layo( zebra      = abap_true
                                        cwidth_opt = 'A'
                                        grid_title = 'Flugverbindungen' ).
 
* Feldkatalog automatisch durch SALV erstellen lassen
    DATA: o_salv TYPE REF TO cl_salv_table.
 
    cl_salv_table=>factory( IMPORTING
                              r_salv_table = o_salv
                            CHANGING
                              t_table      = it_spfli ).
 
    DATA(it_fcat) = cl_salv_controller_metadata=>get_lvc_fieldcatalog( r_columns      = o_salv->get_columns( )
                                                                       r_aggregations = o_salv->get_aggregations( ) ).
 
* im Feldkatalog alle Zellen der Spalte "CITYFROM" des ALV-Grids auf
* editierbar stellen, die restlichen Zellen sind nicht editierbar
    LOOP AT it_fcat ASSIGNING FIELD-SYMBOL(<fcat>).
      CASE <fcat>-fieldname.
        WHEN 'CITYFROM'.
          <fcat>-edit = abap_true.
        WHEN OTHERS.
          <fcat>-edit = abap_false.
      ENDCASE.
    ENDLOOP.
 
* ALV anzeigen
    o_alv->set_table_for_first_display( EXPORTING
                                          i_bypassing_buffer = abap_false
                                          i_save             = 'A'
                                          is_layout          = lv_layout
                                        CHANGING
                                          it_fieldcatalog    = it_fcat
                                          it_outtab          = it_spfli ).
 
* Drucktastenleiste: Button "Ausführen (F8)" entfernen
    DATA: it_exclude_btn TYPE STANDARD TABLE OF rsexfcode WITH DEFAULT KEY.
    it_exclude_btn = VALUE #( ( fcode = 'ONLI' ) ).
 
    CALL FUNCTION 'RS_SET_SELSCREEN_STATUS'
      EXPORTING
        p_status  = '%_00' " akt. Standard-PF-Status des Dypro 2000
      TABLES
        p_exclude = it_exclude_btn.
 
* leere SAP-Toolbar ausblenden
    cl_abap_list_layout=>suppress_toolbar( ).
 
* Focus auf ALV setzen
    cl_gui_alv_grid=>set_focus( control = o_alv ).
 
* Flag für Screen-Status auf ALV-Anzeige setzen
    gv_screen_status = 'IN_ALV'.
  ENDIF.
**********************************************************************
*
* START-OF-SELECTION
*
**********************************************************************
START-OF-SELECTION.
 
* Wir befinden uns im Anzeigebereich des Selektionsbildes
  gv_screen_status = 'IN_SELECTION'.
 
* Trick: leeren Dummy-Screen 2000 anzeigen und intern für das ALV-Grid in
* AT SELECTION-SCREEN OUTPUT als cl_gui_container=>default_screen nutzen
  CALL SELECTION-SCREEN 2000.

Best Answer

The reason why leaving the Selection Screen 2000 doesn't make your return to the previous default Selection Screen (1000) is that you have assigned the incorrect GUI Status %_00 (of the Kernel program RSSYSTDB) to the screen 2000, which is the standard one assigned to the default Selection Screen (1000). Hence, the ABAP kernel thinks that Back is pressed on the main Selection Screen and exits the program.

More specifically, it's the value of the Function Code which is tested by the kernel: in the GUI Status %_00, the Back button corresponds to the function code E, so if you create a custom GUI Status with a button assigned to the function code E, pressing this button will also leave the program.

Solution: for a selection screen called with CALL SELECTION-SCREEN, the default standard GUI Status %_CS is used, so your custom GUI Status should use its Function Codes (CBAC for the Back button), and the default Selection Screen 1000 will then be displayed (in debug, you will see that the ABAP statement after CALL SELECTION-SCREEN 2000 is executed, which was not the case with %_00, and so it will return to the main Selection Screen).

So, one solution is the below one (Edit: adding CRET to exclude F8), but you may choose other solutions now that you understand what the original issue was.

    it_exclude_btn = VALUE #( ( fcode = 'CRET' ) ).
    CALL FUNCTION 'RS_SET_SELSCREEN_STATUS'
      EXPORTING
        p_status  = '%_CS'
      TABLES
        p_exclude = it_exclude_btn.

As one can see, F8 is assigned to CRET in the GUI Status %_CS of RSSYSTDB:

%_CS of RSSYSTDB

The issue is not related to ALV, it's a pure selection screen issue. Here is the minimal code to reproduce the issue (the code doesn't continue after CALL SELECTION-SCREEN 2000 after Back has been pressed):

PARAMETERS dummy1.
SELECTION-SCREEN BEGIN OF SCREEN 2000.
  PARAMETERS dummy2.
SELECTION-SCREEN END OF SCREEN 2000.

AT SELECTION-SCREEN OUTPUT.
  IF sy-dynnr = '2000'.
    DATA it_exclude_btn TYPE STANDARD TABLE OF rsexfcode WITH DEFAULT KEY.
    CALL FUNCTION 'RS_SET_SELSCREEN_STATUS'
      EXPORTING
        p_status  = '%_00' " wrong one: back will leave program
      TABLES
        p_exclude = it_exclude_btn.
  ENDIF.

START-OF-SELECTION.
  CALL SELECTION-SCREEN 2000.
  ASSERT 1 = 1. " Debug helper to set a break-point / never reached

For information, here are the GUI statuses and their main buttons/function codes, depending on the exact context how the selection screen is called (see table legend (*)):

Function SUBMIT (**) CALL SELECTION-SCREEN
... (full screen)
CALL SELECTION-SCREEN
... AS WINDOW (popup)
SUBMIT ... VIA JOB
... (before job is created)
GUI status %_00 %_CS %_CSP %_JB
Enter <empty> <empty> NONE <empty>
Save variant SPOS SPOS SPOS SPOS
Get variant (E) GET GET GET GET
Execute ONLI CRET CRET N/A
Execute and print PRIN N/A N/A N/A
Execute in background SJOB N/A N/A N/A
Exit (E) ENDE CEND N/A ENDE
Cancel (E) ECAN CCAN CCAN ECAN
Back (E) E CBAC N/A E
Schedule in job N/A N/A N/A JOBS

(*) Legend: "(E)" if a function is of type Exit, i.e. triggers AT SELECTION-SCREEN ON EXIT-COMMAND (others trigger AT SELECTION-SCREEN), "" means that pressing Enter corresponds to an empty function code, "N/A" means that the function is not available.

(**) Either SUBMIT without extension, or default selection screen 1000 exists and is shown, or SUBMIT ... USING SELECTION-SCREEN <number> ..., or Transaction Code calling an Executable Program (type 1)

Note that in Selection Screens, if needed to test the function code, the field sscrfields-ucomm should be used as shown in the example below (NB: in Dynpro programming, SY-UCOMM is always to be avoided; complete path: Home > ABAP_PLATFORM_NEW > Classic Screen Programming > General Dynpros > Processing Screens > User Actions on Screens > Reading Function Code):

REPORT ... " or FUNCTION-POOL ...
...
TABLES sscrfields. " mandatory
...
AT SELECTION-SCREEN.
  CASE sy-dynnr.
    WHEN '1000'.
      CASE sscrfields-ucomm.
        WHEN 'ONLI'.
          ...
      ENDCASE.
  ENDCASE.
...
AT SELECTION-SCREEN ON EXIT-COMMAND.
  CASE sy-dynnr.
    WHEN '2000'.
      CASE sscrfields-ucomm.
        WHEN 'CBAC'.
          ...
      ENDCASE.
  ENDCASE.
...
Related Question