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.
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.
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.
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( ).
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.
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( ).
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