This has been a SALV Editable week. Earlier this week, I published a blog on standard application using SALV for editable(
SALV Editable? Yes, as per this Standard SAP Application)
The solution works great if there is an extra button. This extra button – say Edit – would make the SALV editable. This button is required to gain the access of the underlying Grid object (CL_GUI_ALV_GRID). The Grid object than used to set up the editable functionality.
paul.hardy2 had asked if we can remove that extra button and make the SALV editable directly, in
his comment section of my previous blog
SALV Editable? Yes, as per this Standard SAP Application
No more button
The idea was to find an event which gets triggered but before the output is displayed to the user. I did some research, infect lot of research to find an event that would work in both Grid and FullScreen ALV. I played with different events like TOP_OF_PAGE, TOP_OF_LIST, PRINT_TOP_OF_PAGE etc.
Fullscreen ALV triggers TOP_OF_PAGE but not the Grid ALV, as for Grid there is no direct TOP_OF_PAGE. FullScreen ALV triggers it when the top of page is created using the method O_SALV->SET_TOP_OF_LIST( ). Also this would bring up a header in the ALV. For the Grid, You would need to create an object for CL_DD_DOCUMENT, pass it to the Grid object and raise the event TOP_OF_PAGE. Without having the Grid to begin with, can’t assign the header, and thus can’t get the TOP_OF_PAGE event to work.
Event AFTER_REFRESH is the trick, I was looking for :cool:
Event AFTER_REFRESH
Event AFTER_REFRESH gets triggered after system finished rendering ALV – Field catalog parsed, Data sent to the DP (data provider) aka Frontend, Layout applied, Toolbar created, and all other ALV related stuff. Now, how to capture this event when there is no Grid object. So, declared an event handler to handle the event AFTER_REFRESH of class CL_GUI_ALV_GRID. The trick is the registration of the event using the addition
FOR ALL INSTANCES of SET EVENT HANDLER.
"To gain an access to the underlying object and
" do the magic
SET HANDLER lo_event_h->on_after_refresh
FOR ALL INSTANCES
ACTIVATION 'X'.
FOR ALL INSTANCES is quite powerful. It can register the event for any object for that event belongs, even if the object is instantiated after the handler is registered. That’s very useful in this scenario as the Grid object is not yet instantiated.
Avoid Endless Loop Trap
To make the grid editable, either you can pass the LAYOUT-EDIT = ‘X’ with following REFRESH_TABLE_DISPLAY( ) call or method SET_READY_FOR_INPUT call . The thing is, both of these methods would call the method SOFT_REFRESH_TABLE_DISPLAY and would raise the event AFTER_REFRESH. This would again be caught in our event handler. The event handler would make the grid editable again with refresh – so going in the loop.
To avoid this, we would switch off – more technically deregister the event handler. Using the addition ACTIVATION space in the SET HANDLER would do this for us.
"deregister the event handler
SET HANDLER me->on_after_refresh
FOR ALL INSTANCES
ACTIVATION space.
Toolbar
Next is the toolbar. The edit buttons in the toolbar are displayed without any additional work, but for grid there is some special logic which prevents it from creating the edit buttons in the toolbar. This all happens in the method CL_SALV_CONTROLLER_EVENTS=> RAISE_BUILD_UIFUNCTION where only few of the buttons are displayed.
So we will trick the toolbar to add the same missing buttons. To do this, we would need to register the event TOOLBAR for the CL_GUI_ALV_GRID. This would be done same – with using the FOR ALL INSTANCE.
"only for GRID, would need to add the toolbar buttons
IF io_salv->get_display_object( ) = 3.
SET HANDLER lo_event_h->on_toolbar
FOR ALL INSTANCES
ACTIVATION 'X'.
ENDIF.
Single Method to Make it Editable
Not out of the box single method :), but I enclosed all these logic in one single method. Call this method by passing the ALV object before the DISPLAY method, and all done.
The method would register the event AFTER_REFRESH and TOOLBAR (for grid). The class also host the event handler methods in the local class. The event handler would make the grid editable and add the buttons in the toolbar as well. All the complexity for making it editable is hidden and wrapped in this method.
Also this method would control the logic for multiple SALV objects. Optional parameter SENDER for the event handler with the object pool design pattern is used.
" Make grid editable
" call before display
zcl_test_np_salv_model=>set_editable( gr_table ).
In Action
Fullscreen ALV
generated by SALV in Editable mode
ALV Grid generated by SALV in Editable mode
Multiple Grid, only one is editable
Full Method Code
Here is the method ZCL_TEST_NP_SALV_MODEL=>SET_EDITABLE
class ZCL_TEST_NP_SALV_MODEL definition
public
final
create public .public section.
class-methods SET_EDITABLE
importing
!IO_SALV type ref to CL_SALV_TABLE .
PROTECTED SECTION.
PRIVATE SECTION.
class-data o_event_h type ref to OBJECT.
ENDCLASS.
CLASS ZCL_TEST_NP_SALV_MODEL IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_TEST_NP_SALV_MODEL=>SET_EDITABLE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_SALV TYPE REF TO CL_SALV_TABLE
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD set_editable.
DATA: lo_event_h TYPE REF TO lcl_event_handler.
"Event handler
IF zcl_test_np_salv_model=>o_event_h IS NOT BOUND.
CREATE OBJECT zcl_test_np_salv_model=>o_event_h
TYPE lcl_event_handler.
ENDIF.
lo_event_h ?= zcl_test_np_salv_model=>o_event_h.
APPEND io_salv TO lo_event_h->t_salv.
"To gain an access to the underlying object and
" do the magic
SET HANDLER lo_event_h->on_after_refresh
FOR ALL INSTANCES
ACTIVATION 'X'.
"only for GRID, would need to add the toolbar buttons
IF io_salv->get_display_object( ) = 3.
SET HANDLER lo_event_h->on_toolbar
FOR ALL INSTANCES
ACTIVATION 'X'.
ENDIF.
ENDMETHOD.
ENDCLASS.
And the event handler LCL_EVENT_HANDLER
*----------------------------------------------------------------------*
* Event handler ALV events
*----------------------------------------------------------------------*
CLASS lcl_event_handler DEFINITION.
PUBLIC SECTION.
METHODS:
on_after_refresh FOR EVENT after_refresh OF cl_gui_alv_grid
IMPORTING
sender,
on_toolbar FOR EVENT toolbar OF cl_gui_alv_grid
IMPORTING
e_object
e_interactive
sender.
DATA: t_salv TYPE STANDARD TABLE OF REF TO cl_salv_table.
ENDCLASS. "lcl_event_handler DEFINITION
*
CLASS lcl_event_handler IMPLEMENTATION.
METHOD on_after_refresh.
DATA: lo_grid TYPE REF TO cl_gui_alv_grid.
DATA: ls_layout TYPE lvc_s_layo.
DATA: lo_salv TYPE REF TO cl_salv_table.TRY .
LOOP AT t_salv INTO lo_salv.
lo_grid = zcl_test_np_salv_model=>get_grid( lo_salv ).
CHECK lo_grid EQ sender.
"deregister the event handler
SET HANDLER me->on_after_refresh
FOR ALL INSTANCES
ACTIVATION space.
"Set editable
ls_layout-edit = 'X'.
lo_grid->set_frontend_layout( ls_layout ).
lo_grid->set_ready_for_input( 1 ).
ENDLOOP.
CATCH cx_salv_error.
ENDTRY.
ENDMETHOD. "on_AFTER_REFRESH
*
METHOD on_toolbar.
DATA: lo_grid TYPE REF TO cl_gui_alv_grid.
DATA: ls_layout TYPE lvc_s_layo.
DATA: mt_toolbar TYPE ttb_button.
DATA: ls_toolbar LIKE LINE OF mt_toolbar.
DATA: lo_salv TYPE REF TO cl_salv_table.
TRY .
LOOP AT t_salv INTO lo_salv.
lo_grid = zcl_test_np_salv_model=>get_grid( lo_salv ).
IF lo_grid EQ sender.
EXIT.
ELSE.
CLEAR lo_grid.
ENDIF.
ENDLOOP.
CATCH cx_salv_msg.
EXIT.
ENDTRY.
CHECK lo_grid IS BOUND.
CHECK lo_grid->is_ready_for_input( ) = 1.
*... Toolbar Button CHECK
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_check.
ls_toolbar-quickinfo = text-053. "Eingaben prfen
ls_toolbar-icon = icon_check.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Seperator
CLEAR ls_toolbar.
ls_toolbar-function = '&&SEP01'.
ls_toolbar-butn_type = 3.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Button CUT
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_loc_cut.
ls_toolbar-quickinfo = text-046. "Ausschneiden
ls_toolbar-icon = icon_system_cut.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Button COPY
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_loc_copy.
ls_toolbar-quickinfo = text-045. " Kopieren
ls_toolbar-icon = icon_system_copy.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Button PASTE OVER ROW
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_loc_paste.
ls_toolbar-quickinfo = text-047.
ls_toolbar-icon = icon_system_paste.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Button PASTE NEW ROW
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_loc_paste_new_row.
ls_toolbar-quickinfo = text-063.
ls_toolbar-icon = icon_system_paste.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Button UNDO
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_loc_undo.
ls_toolbar-quickinfo = text-052. "Rckgngig
ls_toolbar-icon = icon_system_undo.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Separator
CLEAR ls_toolbar.
ls_toolbar-function = '&&SEP02'.
ls_toolbar-butn_type = 3.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Button APPEND ROW
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_loc_append_row.
ls_toolbar-quickinfo = text-054. "Zeile anhngen
ls_toolbar-icon = icon_create.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Button INSERT ROW
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_loc_insert_row.
ls_toolbar-quickinfo = text-048. "Zeile einfgen
ls_toolbar-icon = icon_insert_row.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Button DELETE ROW
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_loc_delete_row.
ls_toolbar-quickinfo = text-049. "Zeile lschen
ls_toolbar-icon = icon_delete_row.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Button COPY ROW
CLEAR ls_toolbar.
ls_toolbar-function = cl_gui_alv_grid=>mc_fc_loc_copy_row.
ls_toolbar-quickinfo = text-051. "Duplizieren
ls_toolbar-icon = icon_copy_object.
ls_toolbar-disabled = space.
APPEND ls_toolbar TO mt_toolbar.
*... Toolbar Separator
CLEAR ls_toolbar.
ls_toolbar-function = '&&SEP03'.
ls_toolbar-butn_type = 3.
APPEND ls_toolbar TO mt_toolbar.
APPEND LINES OF mt_toolbar TO e_object->mt_toolbar.
ENDMETHOD. "on_toolbar
ENDCLASS. "lcl_event_handler IMPLEMENTATION