Showing posts with label SALV. Show all posts
Showing posts with label SALV. Show all posts

Sunday, May 7, 2017

Display table content in a popup window via SALV

If you have a list of various db tables with different structure (selected by specific field name) you may want add a preview of each ones content via popup window. But field name could be a variable of unknown type. Below coding shows a way how to reach this functionality, it uses dynamic data creation, dynamic Open SQL and SALV class.

Note: Sorry for the ugly subroutine surrounding ;-) I placed this functionality into an old program, where is the subroutine triggered by event  AT LINE-SELECTION working  together with variables provided by HIDE command. The popup window nicely works with selection screen.



TYPES tyv_sql_line TYPE c LENGTH 72.

*&---------------------------------------------------------------------*
*&      Form  show_table_content
*&---------------------------------------------------------------------*
*       Show table content in a popup window by specific field
*----------------------------------------------------------------------*
FORM show_table_content USING p_tablename p_fieldname p_fieldvalue.

  DATA: lt_sql_where   TYPE STANDARD TABLE OF tyv_sql_line,
              lv_sql_where   LIKE LINE OF lt_sql_where,
              rv_dref        TYPE REF TO data,
              rcl_alv        TYPE REF TO cl_salv_table,
              lx_msg         TYPE REF TO cx_salv_msg.

  FIELD-SYMBOLS: <itab> TYPE ANY TABLE.

  CLEAR lv_sql_where.
  CLEAR lt_sql_where.

  CONCATENATE p_fieldname ' = ' '`' p_fieldvalue '`' INTO lv_sql_where RESPECTING BLANKS.
  APPEND lv_sql_where TO lt_sql_where.

  CREATE DATA rv_dref TYPE TABLE OF (p_tablename).
  ASSIGN rv_dref->* TO <itab>.

  SELECT * FROM (p_tablename)
  INTO TABLE <itab>
  WHERE (lt_sql_where).

  IF <itab> IS ASSIGNED.

    TRY.
        cl_salv_table=>factory(
        IMPORTING
          r_salv_table = rcl_alv
        CHANGING
          t_table      = <itab> ).
      CATCH cx_salv_msg INTO lx_msg.
    ENDTRY.

    rcl_alv->set_screen_popup(
      start_column = 25
      end_column   = 150
      start_line   = 15
      end_line     = 22
    ).

    rcl_alv->display( ).

  ENDIF.

ENDFORM.                    "show_table_content



The popup looks like e.g.



Valuable source for ALV popup 


Saturday, April 15, 2017

User parameters comparison tool (USR05)

This article just offers a small fast food program comparing parameters between two users. Some transactions use bunch of these params. During a tuning of a new user or in case of troubles is handy to compare them.

I was surprised that SUIM tx. does not offer such functionality. To keep all the comparison abilities on one place, I placed there buttons calling SUIM comparison tools too.

Because we use also an other PARID/PARVA based custom table with the same structure as USR05, I placed an option also to compare such table. You can add there as much radio buttons as you want.


How does it look like?


Input screen





Result screen


  • Red - parameter exists just on one side
  • Yellow - parameter exists on both sides, but the actual value differs
  • Green - parameter exists on both sides and the value fits


Sorted by Parameter ID




Sorted by equality status 





The source code:



*&---------------------------------------------------------------------*
*& Report  Y_USER_CMP
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*

REPORT y_user_cmp.

TYPES: BEGIN OF sty_param_both.
TYPES: parid   TYPE  memoryid.   " ID line including both sides, used later for sorting
TYPES: parid1  TYPE  abap_bool.
TYPES: parva1  TYPE  xuvalue.
TYPES: parid2  TYPE  abap_bool.  " The second id has to be stored as well because we need to distinguish the case where id is present within both tables, but empty on one side
TYPES: parva2  TYPE  xuvalue.
TYPES: partext TYPE  as4text.
TYPES: status  TYPE  c LENGTH 1. " S = successfull comparison, E = id not exists on both sides, W = ID exists but values differ
TYPES: t_color TYPE  lvc_t_scol.
TYPES: END OF sty_param_both.

TYPES: tty_param_both TYPE STANDARD TABLE OF sty_param_both.


*----------------------------------------------------------------------*
*       CLASS lcl_alv DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_alv DEFINITION.

  PUBLIC SECTION.
    METHODS:
      constructor
        IMPORTING
          iv_usr1    TYPE xubname
          iv_usr2    TYPE xubname
          iv_tabname TYPE tabname
          it_param   TYPE tty_param_both,
      generate_alv.

  PRIVATE SECTION.

    TYPES: BEGIN OF gt_t_heading,
      operand(12) TYPE c,
      valtyp      TYPE char30,
      client      TYPE char10,
      system      TYPE char30,
    END   OF gt_t_heading.

    DATA:   v_usr1    TYPE xubname,
            v_usr2    TYPE xubname,
            v_tabname TYPE tabname,
            t_param   TYPE tty_param_both,
            o_salv    TYPE REF TO cl_salv_table,
            o_header  TYPE REF TO cl_salv_form_layout_grid,
            o_h_label TYPE REF TO cl_salv_form_label,
            o_h_flow  TYPE REF TO cl_salv_form_layout_flow,
            o_ex      TYPE REF TO cx_root.

    METHODS:
      set_columns,
      set_header,
      set_rows_color.

ENDCLASS.                    "lcl_alv DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_alv IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_alv IMPLEMENTATION.

  METHOD: constructor.

    super->constructor( ).

    v_usr1     = iv_usr1.
    v_usr2     = iv_usr2.
    v_tabname  = iv_tabname.
    t_param    = it_param.

  ENDMETHOD.                    "constructor

  METHOD generate_alv.

    TRY.
        cl_salv_table=>factory(
        IMPORTING
          r_salv_table = o_salv
        CHANGING
          t_table      = t_param
        ).
      CATCH cx_root INTO o_ex.
        MESSAGE o_ex TYPE 'E'.
    ENDTRY.

    me->set_header( ).
    me->set_columns( ).
    me->set_rows_color( ).

    o_salv->display( ).

  ENDMETHOD.                    "constructor

  METHOD set_columns.

    DATA: lo_columns TYPE REF TO cl_salv_columns_table,
          lo_column  TYPE REF TO cl_salv_column_table,
          lv_title_s TYPE scrtext_s,
          lv_title_m TYPE scrtext_m,
          lv_title_l TYPE scrtext_l.

    lo_columns = o_salv->get_columns( ).
    lo_columns->set_optimize( abap_true ).

    TRY.

        lv_title_s = v_usr1.
        CONCATENATE v_usr1 space 'value' INTO lv_title_m RESPECTING BLANKS.
        CONCATENATE v_usr1 space 'value' INTO lv_title_l RESPECTING BLANKS.
        lo_column ?= lo_columns->get_column( 'PARVA1' ).
        lo_column->set_short_text( lv_title_s ).
        lo_column->set_medium_text( lv_title_m ).
        lo_column->set_long_text( lv_title_l ).

        CLEAR: lv_title_s, lv_title_m, lv_title_l.
        lv_title_s = v_usr2.
        CONCATENATE v_usr2 space 'value' INTO lv_title_m RESPECTING BLANKS.
        CONCATENATE v_usr2 space 'value' INTO lv_title_l RESPECTING BLANKS.
        lo_column ?= lo_columns->get_column( 'PARVA2' ).
        lo_column->set_short_text( lv_title_s ).
        lo_column->set_medium_text( lv_title_m ).
        lo_column->set_long_text( lv_title_l ).

        lo_column ?= lo_columns->get_column( 'PARID1' ).
        lo_column->set_visible( abap_false ).

        lo_column ?= lo_columns->get_column( 'PARID2' ).
        lo_column->set_visible( abap_false ).

        lo_column ?= lo_columns->get_column( 'STATUS' ).
        lo_column->set_visible( abap_false ).

      CATCH cx_salv_not_found.                          "#EC NO_HANDLER
    ENDTRY.

  ENDMETHOD.                    "set_columns

  METHOD set_header.

    " Simplified RSUSR050 code for header

    DATA: lo_grid        TYPE REF TO cl_salv_form_layout_grid,
          lo_label       TYPE REF TO cl_salv_form_label,    "#EC NEEDED
          lo_text        TYPE REF TO cl_salv_form_text,     "#EC NEEDED
          lv_row         TYPE        i,
          lv_column      TYPE        i,
          lv_title       TYPE        c LENGTH 100.

    CONCATENATE 'Comparison of user parameters for table ' space v_tabname INTO lv_title RESPECTING BLANKS.

    DATA: lt_heading  TYPE STANDARD TABLE OF gt_t_heading,
          ls_heading  LIKE LINE OF lt_heading,
          lv_lsind      TYPE i.

    ls_heading-operand = 'User'.
    ls_heading-valtyp  = 'Name'.
    ls_heading-client  = 'Client'.
    ls_heading-system  = 'System'.
    APPEND ls_heading TO lt_heading.

    CLEAR ls_heading.
    ls_heading-operand = 'A'.
    ls_heading-valtyp  = v_usr1.
    ls_heading-client  = sy-mandt.
    ls_heading-system  = sy-sysid.
    APPEND ls_heading TO lt_heading.

    CLEAR ls_heading.
    ls_heading-operand = 'B'.
    ls_heading-valtyp  = v_usr2.
    ls_heading-client  = sy-mandt.
    ls_heading-system  = sy-sysid.
    APPEND ls_heading TO lt_heading.

    CLEAR: lv_row, lv_column.

    CREATE OBJECT lo_grid.

    lo_grid->create_header_information(
      row     = 1
      column  = 1
      colspan = 20
      text    = lv_title
    ).

    lo_grid->add_row( ).

    READ TABLE lt_heading INTO ls_heading INDEX 1.
    lv_column = 11.
    lo_label = lo_grid->create_label( row    =  3
    column  =  2
    text    =  ls_heading-operand ).

    lo_label = lo_grid->create_label( row    =  3
    column  =  5
    text    =  ls_heading-valtyp ).

    lv_column = lv_column + 10.
    lo_label = lo_grid->create_label( row    =  3
    column  =  lv_column
    text    =  ls_heading-client ).

    lv_column = lv_column + 10.
    lo_label = lo_grid->create_label( row     =  3
    column  =  lv_column
    text    =  ls_heading-system ).

    lv_row = 4.
    LOOP AT lt_heading INTO ls_heading FROM 2.
      lv_column = 11.
      lo_text = lo_grid->create_text( row     =  lv_row
      column  =  2
      text    =  ls_heading-operand ).

      lo_text = lo_grid->create_text(   row     =  lv_row
      column  =  5
      text    =  ls_heading-valtyp ).

      lv_column = lv_column + 10.
      lo_text = lo_grid->create_text(   row     =  lv_row
      column  =  lv_column
      text    =  ls_heading-client ).

      lv_column = lv_column + 10.
      lo_text = lo_grid->create_text(   row     =  lv_row
      column  =  lv_column
      text    =  ls_heading-system ).
      lv_row  = lv_row + 1.
    ENDLOOP.

    o_salv->set_top_of_list( lo_grid ).

  ENDMETHOD.                    "set_header

  METHOD set_rows_color.

    DATA: lo_cols_tab TYPE REF TO cl_salv_columns_table,
          lt_s_color TYPE lvc_t_scol,
          ls_s_color TYPE lvc_s_scol.

    FIELD-SYMBOLS: <fs_param> LIKE LINE OF t_param.
    LOOP AT t_param ASSIGNING <fs_param>.

      IF ( <fs_param>-parid1 IS INITIAL ) OR ( <fs_param>-parid2 IS INITIAL ).
        ls_s_color-color-col = col_negative.
      ELSE.
        IF ( <fs_param>-parva1 NE <fs_param>-parva2 ).
          ls_s_color-color-col = 3. " yellow
        ELSE.
          ls_s_color-color-col = col_positive.
        ENDIF.
      ENDIF.

      ls_s_color-color-int = 0.
      ls_s_color-color-inv = 0.
      APPEND ls_s_color TO lt_s_color.
      CLEAR  ls_s_color.

      <fs_param>-t_color = lt_s_color.
      CLEAR  lt_s_color.
    ENDLOOP.

    lo_cols_tab = o_salv->get_columns( ).
    TRY.
        lo_cols_tab->set_color_column( 'T_COLOR' ).
      CATCH cx_salv_data_error.
    ENDTRY.

  ENDMETHOD.                    "set_rows_color

ENDCLASS.                    "lcl_alv IMPLEMENTATION

*----------------------------------------------------------------------*
*       CLASS lcl_user_cmp DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_user_cmp DEFINITION.

  PUBLIC SECTION.

    METHODS compare_users
              IMPORTING iv_usr1       TYPE xubname
                        iv_usr2       TYPE xubname
                        iv_tabname    TYPE tabname
                        iv_sort_parid TYPE abap_bool.

    CLASS-METHODS get_instance RETURNING value(ro_obj) TYPE REF TO lcl_user_cmp.
    CLASS-METHODS check_authorization.

  PRIVATE SECTION.

    TYPES: tty_param      TYPE STANDARD TABLE OF usparam.

    CLASS-DATA: o_user_cmp TYPE REF TO lcl_user_cmp.

    DATA: o_alv TYPE REF TO lcl_alv.

    METHODS get_user_param
              IMPORTING iv_usr     TYPE xubname
              EXPORTING et_param  TYPE tty_param.

ENDCLASS.                    "lcl_user_cmp DEFINITION


*----------------------------------------------------------------------*
*       CLASS lcl_user_cmp IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_user_cmp IMPLEMENTATION.

  METHOD compare_users.

    DATA: lt_param1     TYPE tty_param,
          lt_param2     TYPE tty_param,
          lt_param_both TYPE STANDARD TABLE OF sty_param_both,
          ls_param_both LIKE LINE OF lt_param_both.

    me->get_user_param(
          EXPORTING
          iv_usr    = iv_usr1
          IMPORTING
            et_param = lt_param1
    ).

    me->get_user_param(
          EXPORTING
            iv_usr    = iv_usr2
          IMPORTING
            et_param = lt_param2
    ).

    FIELD-SYMBOLS: <fs_param> TYPE usparam.

    " store whole first table
    LOOP AT lt_param1 ASSIGNING <fs_param>.
      CLEAR ls_param_both.
      ls_param_both-parid   = <fs_param>-parid.
      ls_param_both-parid1  = abap_true.
      ls_param_both-parva1  = <fs_param>-parva.
      ls_param_both-partext = <fs_param>-partext.
      ls_param_both-status  = 'E'. " ID does not fit by default
      APPEND ls_param_both TO lt_param_both.
    ENDLOOP.

    " loop over second param table
    LOOP AT lt_param2 ASSIGNING <fs_param>.

      CLEAR ls_param_both.

      READ TABLE lt_param_both INTO ls_param_both WITH KEY parid = <fs_param>-parid.
      IF sy-subrc EQ 0.
        " The same ID already exists, alter existing row
        ls_param_both-parid2  = abap_true.
        ls_param_both-parva2  = <fs_param>-parva.

        IF ls_param_both-parva1 EQ <fs_param>-parva.
          ls_param_both-status  = 'S'.
        ELSE.
          ls_param_both-status  = 'W'.
        ENDIF.

        MODIFY lt_param_both FROM ls_param_both INDEX sy-tabix TRANSPORTING parid2 parva2 status.
      ELSE.
        " Insert complete new row
        ls_param_both-parid   = <fs_param>-parid.
        ls_param_both-parid2  = abap_true.
        ls_param_both-parva2  = <fs_param>-parva.
        ls_param_both-partext = <fs_param>-partext.
        ls_param_both-status  = 'E'.
        APPEND ls_param_both TO lt_param_both.
      ENDIF.
    ENDLOOP.

    IF iv_sort_parid EQ abap_true.
      SORT lt_param_both BY parid.
    ELSE.
      SORT lt_param_both BY status.
    ENDIF.

    FREE o_alv.

    CREATE OBJECT o_alv
      EXPORTING
        iv_usr1    = iv_usr1
        iv_usr2    = iv_usr2
        iv_tabname = iv_tabname
        it_param   = lt_param_both.

    o_alv->generate_alv( ).

  ENDMETHOD.                    "compare_users

  METHOD get_instance.

    IF o_user_cmp IS NOT BOUND.
      CREATE OBJECT o_user_cmp.
    ENDIF.

    ro_obj = o_user_cmp.

  ENDMETHOD.                    "get_instance

  METHOD check_authorization.

    CLEAR: sy-msgid, sy-msgty, sy-msgno, sy-msgv1, sy-msgv2, sy-msgv3, sy-msgv4.

    CALL FUNCTION 'AUTHORITY_CHECK_TCODE'
      EXPORTING
        tcode  = 'SU01D'
      EXCEPTIONS
        ok     = 0
        not_ok = 1
        OTHERS = 2.

    IF sy-subrc <> 0.
      IF sy-msgid IS INITIAL OR sy-msgty IS INITIAL.
        MESSAGE i172(00) DISPLAY LIKE 'I' WITH sy-tcode.
      ELSE.
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        DISPLAY LIKE sy-msgty
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      ENDIF.
      LEAVE PROGRAM.
    ENDIF.

  ENDMETHOD.                    "check_authorization

  METHOD get_user_param.

    CALL FUNCTION 'SUSR_USER_PARAMETERS_GET'
      EXPORTING
        user_name           = iv_usr
        with_text           = space
      TABLES
        user_parameters     = et_param
      EXCEPTIONS
        user_name_not_exist = 1
        OTHERS              = 2.

  ENDMETHOD.                    "check_authorization

ENDCLASS.                    "lcl_user_cmp IMPLEMENTATION


DATA:  go_user_cmp TYPE REF TO lcl_user_cmp,
       gv_tabname  TYPE tabname.

TABLES sscrfields.

" Usernames
SELECTION-SCREEN BEGIN OF BLOCK bl_users WITH FRAME TITLE tx_01.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT 1(6) tx_02 FOR FIELD p_usr1.
PARAMETERS p_usr1 TYPE xubname MATCHCODE OBJECT user_addr.
SELECTION-SCREEN COMMENT 40(6) tx_03 FOR FIELD p_usr2.
PARAMETERS p_usr2 TYPE xubname MATCHCODE OBJECT user_addr.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK bl_users.

" Table choice
SELECTION-SCREEN BEGIN OF BLOCK bl_tabs WITH FRAME TITLE tx_08.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS r_tab1 RADIOBUTTON GROUP rg1.
SELECTION-SCREEN COMMENT 4(23) tx_04 FOR FIELD r_tab1.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS r_tab2 RADIOBUTTON GROUP rg1.
SELECTION-SCREEN COMMENT 4(23) tx_05 FOR FIELD r_tab2.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK bl_tabs.

" Sort choice
SELECTION-SCREEN BEGIN OF BLOCK bl_sort WITH FRAME TITLE tx_09.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS r_sort1 RADIOBUTTON GROUP rg2.
SELECTION-SCREEN COMMENT 4(24) tx_06 FOR FIELD r_sort1.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS r_sort2 RADIOBUTTON GROUP rg2.
SELECTION-SCREEN COMMENT 4(24) tx_07 FOR FIELD r_sort2.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK bl_sort.

SELECTION-SCREEN PUSHBUTTON 1(25) tx_10 USER-COMMAND onli.

************************************************************************
INITIALIZATION.
************************************************************************
  " Authorization
  lcl_user_cmp=>check_authorization( ).

  " Get main class instance
  go_user_cmp = lcl_user_cmp=>get_instance( ).

  " Screen buttons for SUIM comaprison programs
  SELECTION-SCREEN : FUNCTION KEY 1.
  SELECTION-SCREEN : FUNCTION KEY 2.
  SELECTION-SCREEN : FUNCTION KEY 3.
  SELECTION-SCREEN : FUNCTION KEY 4.

  " Selection screen texts
  tx_01 = 'Compare user parameters for:'.
  tx_02 = 'User A'.
  tx_03 = 'User B'.
  tx_04 = 'User parameters (USR05)'.
  tx_05 = 'User parameters (ZPC01)'.
  tx_06 = 'Sort by PARAM id (ABC)'.
  tx_07 = 'Sort by Differences'.
  tx_08 = 'Choose parameter table'.
  tx_09 = 'Choose sort'.
  tx_10 = 'Compare user parameters'.
  sscrfields-functxt_01 = 'Compare Users'.
  sscrfields-functxt_02 = 'Roles'.
  sscrfields-functxt_03 = 'Profiles'.
  sscrfields-functxt_04 = 'Authorizations'.


************************************************************************
AT SELECTION-SCREEN.
************************************************************************

  CASE sy-ucomm.
    WHEN 'FC01'.
      SUBMIT rsusr050 VIA SELECTION-SCREEN USING SELECTION-SET 'SAP&_BENUTZER' AND RETURN.
    WHEN 'FC02'.
      SUBMIT rsusr050 VIA SELECTION-SCREEN USING SELECTION-SET 'SAP&_ROLLE' AND RETURN.
    WHEN 'FC03'.
      SUBMIT rsusr050 VIA SELECTION-SCREEN USING SELECTION-SET 'SAP&_PROFILE' AND RETURN.
    WHEN 'FC04'.
      SUBMIT rsusr050 VIA SELECTION-SCREEN USING SELECTION-SET 'SAP&_BERECHTIG' AND RETURN.
    WHEN OTHERS.
      IF ( p_usr1 IS INITIAL ) OR ( p_usr2 IS INITIAL ).
        MESSAGE e279(01) DISPLAY LIKE 'I'.
      ENDIF.
  ENDCASE.


************************************************************************
START-OF-SELECTION.
************************************************************************

  " Run comparison for table:
  CASE abap_true.
    WHEN r_tab1.
      gv_tabname = 'USR05'.
    WHEN r_tab2.
      gv_tabname = 'ZUSER_TAB'.
  ENDCASE.

  go_user_cmp->compare_users( iv_usr1       = p_usr1
                              iv_usr2       = p_usr2
                              iv_tabname    = gv_tabname
                              iv_sort_parid = r_sort1
                            ).

END-OF-SELECTION.

Tuesday, May 31, 2016

How to manually refresh an ALV (CL_SALV_TABLE) with set events


SALV is beautiful class offering many useful functions including famous automatic setup of field catalog. Everyone tries to dig his own ALV tunnel to work with grids. SALV looks as an excellent option, sure. But almost everything has its own BUT… SALV is not an exception. Let’s start my REFRESH journey.

Note: There e.g. class cl_gui_alv_grid with different behavior.

1) SALV without events

Imagine, we have straight forward setup. One screen with ALV grid inside custom container, all the stuff is  loaded within PBO section.

TOP include


Some TOP include should contain something like:

CONSTANTS gc_alv_kbed_container_name TYPE c LENGTH 11 VALUE 'CONTROL_ALV'.
DATA: gcr_container   TYPE REF TO cl_gui_custom_container,
            gcr_alv_control TYPE REF TO lcl_kbed_alv_control.


PBO ALV loader


MODULE d0100_alv_init OUTPUT.

  IF gcr_container IS NOT BOUND.
    CREATE OBJECT gcr_container
      EXPORTING
        container_name = gc_alv_kbed_container_name
      EXCEPTIONS
        others         = 1.
    IF sy-subrc NE 0.
      MESSAGE a001.
    ENDIF.

    CREATE OBJECT gcr_alv_control
      EXPORTING
        it_kbed                  = gt_kbed         " input global kbed table for ALV
        icr_container         = gcr_container
        iv_dynnr                = sy-dynnr.
    gcr_alv_control->display_output( ).
  ELSE.
    gcr_alv_control->refresh_alv( it_kbed = gt_kbed ).
  ENDIF.

ENDMODULE.                    


The constructor of our custom class could look like e.g.

  CLASS lcl_kbed_alv_control IMPLEMENTATION.

    METHOD constructor.

      " get data for ALV
      me->set_data( it_kbed ).

      " create ALV object by factory
      TRY.
          cl_salv_table=>factory(
            EXPORTING
              r_container  = icr_container
            IMPORTING
              r_salv_table = pvcr_alv
            CHANGING
              t_table      = me->pvt_kbed_alv ).
        CATCH cx_salv_msg INTO pvcx_root.
          MESSAGE pvcx_root TYPE 'E'.
      ENDTRY.

    ENDMETHOD.                   

The Refresh method 

    METHOD refresh_alv.

      me->set_data( it_kbed ).
      me->pvcr_alv->refresh( refresh_mode = if_salv_c_refresh=>full ).
      cl_gui_cfw=>flush( ).

    ENDMETHOD.           

Everything works fine. Container and ALV object are created just once in PBO. Every additional screen load causes just refresh of itab inside the ALV grid. Every sort or filter is kept. So, there is no problem so far.

2) SALV with events

Now we need to add some events, e.g. cell double click actions, e.g. adding of a new function. So some handlers are now taken into action. 

      " Register Events
      pvcr_events 
= pvcr_alv->get_event( ).
      
SET HANDLER me->on_link_click       FOR pvcr_events.
      
SET HANDLER me->on_cell_doubleclick FOR pvcr_events.
      
SET HANDLER me->on_added_function   FOR pvcr_events.

Now the game has changed. Our custom refresh methods is no longer working. Why?

We can set up a full refresh mode and there is still no effect? Even static method flush of cl_gui_cfw does not help.

      me->pvcr_alv->refresh( refresh_mode = if_salv_c_refresh=>full ).
      cl_gui_cfw=>flush( ).

So what's wrong?

In debug we can observe the different behavior:

The first picture shows scenario without events 

Everything works fine, refresh takes place.


The second one shows scenario with events 

Ups, suddenly we are kicked away from the method. No actual refresh is done at all.



How to solve refresh in this case?

We can create ALV every time screen is loaded. So PBO module could look like:

  " Refresh screen elements
  IF gcr_container IS BOUND.
    FREE gcr_alv_control.
    gcr_container->free( ).
  ENDIF.

  CREATE OBJECT gcr_container
    EXPORTING
      container_name = gc_alv_kbed_container_name
    EXCEPTIONS
      others         = 1.
  IF sy-subrc NE 0.
    MESSAGE a001.
  ENDIF.

  CREATE OBJECT gcr_alv_control
    EXPORTING
      it_kbed           = ls_kbed[]         " input global kbed table for ALV
      icr_container   = gcr_container
      iv_dynnr          = sy-dynnr.

  gcr_alv_control->display_output( ).



That's easy solution, fine, but what about keeping filters, sorting, any status of ALV object? For this case above trick does not work.



Refresh ala Naimesh 

The below code is inspired by Naimesh Patel's article "Editable SALV model". The goal is to call actual refresh method of ALV grid object. 


We need a bit rebuild the display method of upper custom ALV object.

    METHOD display_output.
      me->set_columns( ).
      me->set_alv_func_tools( ).
      me->set_layout( ).
      me->set_toolbar( ).

      DATA: lo_alv_mod TYPE REF TO cl_salv_model.

      lo_alv_mod ?= me->pvcr_alv.   
      CREATE OBJECT pvcr_salv_model.   
      pvcr_salv_model->get_model( io_model = lo_alv_mod ).


      me->pvcr_alv->display( ).   " SALV display method
    ENDMETHOD.                  



Also custom refresh_alv method needs some tuning. The only difference in comparing with Naimesh solution is type of lo_full_adap class, I used cl_salv_grid_adapter instead of cl_salv_fullscreen_adapter, otherwise it fell into casting error.

    METHOD refresh_alv.

      DATA: lo_grid   TYPE REF TO cl_gui_alv_grid,
            lo_full_adap TYPE REF TO cl_salv_grid_adapter. "cl_salv_fullscreen_adapter,


      me->set_data( it_kbed ).
      me->pvcr_salv_model->get_adapter( ).
      lo_full_adap ?= me->pvcr_salv_model->o_adapter.
      lo_grid = lo_full_adap->get_grid( ).
      lo_grid->refresh_table_display( ).


    ENDMETHOD.               


Now everything is fine. We have just one SALV object in memory keeping all sorts, filters and any status. We are just populating a new data into the grid. Everything works even with events, starting new transactions on cell double click.


Just for illustration I added some sample code how custom ALV class could look like. I removed many things to keep things simple for now. Sorry, I did not make any complete example. It's just a light version of real coding. But together with Naimesh example it is possible to catch the idea.

*----------------------------------------------------------------------*
*  Define the Local class inheriting from the CL_SALV_MODEL_LIST
*  to get an access of the model, controller and adapter which inturn
*  provides the Grid Object
*----------------------------------------------------------------------*
  CLASS lcl_salv_model DEFINITION INHERITING FROM cl_salv_model_list.
    PUBLIC SECTION.
      DATA: o_control TYPE REF TO cl_salv_controller_model,
            o_adapter TYPE REF TO cl_salv_adapter.
      METHODS:
         get_model
          IMPORTING
            io_model TYPE REF TO cl_salv_model,
         get_controller,
         get_adapter.
    PRIVATE SECTION.
      DATA: lo_model TYPE REF TO cl_salv_model.
  ENDCLASS.                    "LCL_SALV_MODEL DEFINITION



*----------------------------------------------------------------------*
* LCL_SALV_MODEL implementation
*----------------------------------------------------------------------*
  CLASS lcl_salv_model IMPLEMENTATION.
    METHOD get_model.
*   save the model
      lo_model = io_model.
    ENDMETHOD.
    METHOD get_controller.
*   save the controller
      o_control = lo_model->r_controller.
    ENDMETHOD.
    METHOD get_adapter.
*   save the adapter from controller
      o_adapter ?= lo_model->r_controller->r_adapter.
    ENDMETHOD.
  ENDCLASS.                    "LCL_SALV_MODEL IMPLEMENTATION



*----------------------------------------------------------------------*
*       CLASS lcl_kbed_alv_control DEFINITION
*----------------------------------------------------------------------*
* Main ALV class controling KBED table display
*----------------------------------------------------------------------*
  CLASS lcl_kbed_alv_control DEFINITION.
*
    PUBLIC SECTION.

      METHODS:
*     load data
        constructor
          IMPORTING
            it_kbed           TYPE ltty_kbed " ALV data table
            icr_container     TYPE REF TO cl_gui_custom_container
            iv_dynnr          TYPE sydynnr,
        refresh_alv
          IMPORTING
            it_kbed           TYPE ltty_kbed, " ALV data table
*     generate ALV output grid
        display_output.

    PRIVATE SECTION.

      DATA: pvcr_alv          TYPE REF TO cl_salv_table,
            pvcr_salv_model   TYPE REF TO lcl_salv_model,
            pvt_kbed_alv         TYPE STANDARD TABLE OF lsty_kbed_alv,
            pvcx_root               TYPE REF TO cx_root,
            pvcr_columns         TYPE REF TO cl_salv_columns_table,
            pvcr_funcs              TYPE REF TO cl_salv_functions_list,
            pvcr_events            TYPE REF TO cl_salv_events_table,
            pvcr_display           TYPE REF TO cl_salv_display_settings.

      METHODS:
        add_toolbar_function
            IMPORTING
              iv_name    TYPE c
              iv_icon    TYPE string
              iv_text    TYPE c
              iv_tooltip TYPE c,
*       transform data
          set_data
            IMPORTING it_kbed   TYPE ltty_kbed,
          set_alv_func_tools,
          set_layout,
          set_toolbar,
          set_columns,
*       event's method
          on_link_click FOR EVENT link_click OF cl_salv_events_table IMPORTING row column, " event for checkbox
          on_cell_doubleclick FOR EVENT double_click OF cl_salv_events_table IMPORTING row column, " normal double click/ hotspot is not needed in this case
          on_added_function FOR EVENT added_function OF cl_salv_events_table IMPORTING e_salv_function.
  ENDCLASS.                    " lcl_kbed_alv_control DEFINITION