Tuesday, 2 August 2022

Editable CL_SALV_TABLE after release 756

Ever since the CL_SALV_TABLE class was released, one question was ever present – how to make it editable? For years the answer lied in taking advantage of the inheritance of the CL_SALV_TABLE, as presented in this post: http://zevolving.com/2008/12/salv-table-10-editable-salv-model-overcome-the-restriction-of-salv-model/.

I was among those using this method. But then the Release 756 came. And suddenly, all ALVs using it suddenly started reported error after error. I dived in and investigated the issue. To my surprise, I discovered that the very basis of this “edit-hack” was gone. The CL_SALV_TABLE class was no longer in the inheritance tree which enabled it to work!

And so followed combing through the provided interfaces in an effort to find a new way. And lo and behold! A way I indeed found.

In this post, I will share with you how I achieved CL_SALV_TABLE editable upon button-press, complete with F4 references and save function in post-release 756 environment.

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP ABAP Tutorial and Materials, SAP ABAP Guides
Editable CL_SALV_TABLE

New interfaces, new possibilities

The most obvious thing was the presence of several interfaces in the class. Most of them provide functionality which was previously inherited. But among them I found something curious indeed – a method called “Extendable_Grid_API( )”. On its own, the returned interface doesn’t seem all that interesting, but it provides a method for obtaining yet another interface, this one called “Editable_Restricted( )”. Now this seemed promising!

Some further digging revealed another method within this interface, the “Set_Attributes_For_Columnname( )”. And there was an option for a parameter “All_Cells_Input_Enabled”. I set it to true and eureka! My ALV was suddenly editable!

Editable column

So, what is needed to make a column editable? From the CL_SALV_TABLE instance (obtained from factory as usual), get the reference from the method extendable_grid_api( ) and then from it the returning parameter from editable_restricted( ). On it, call the method set_attributes_for_columnname( ). Provide the name of the column and the parameter all_cells_input_enabled as true. And you’re done, that column is now editable!

F4 help generating

When we have editable columns, it sure is nice to also have F4 help provided as well. Fortunately, it’s quite easy. If the column type is a regular one, it’s even present right there for you from the start. Now, we often have types that are our own. For those, it is enough to add DDIC reference to the column. Just get the columns from the CL_SALV_TABLE instance (using the get_columns( ) method), from them select the relevant column using the get_column( ) method. There you can set the DDIC reference via the set_ddic_reference( ) method and you’re good to go!

Save edited values

The user put some values in the ALV and now we’d like to save them. Cl_SALV_TABLE has no check for data changed, and you’ll notice that the data table is not changed by the user inputs if you debug it. So, where do we get the new data? The answer is, in the data table. But only after we tell the system we want them there. The previously mentioned interface returned by the “editable_restricted( )” method has a method called “validate_changed_data( )”. This method returns a boolean if the changed data are valid or not. But more than that, when they are valid, it writes them in the data table we have. And we can easily access them from there (sure, we do need to check the whole data table instead of having just the changes presented, but it’s better than nothing).

Step-by-step guide


And now we put it all together to achieve an ALV with button-enabled edit, F4 help and save button:

1. Create CL_SALV_TABLE from factory as usual. Do note that the t_data table will be where the changed data will be. And therefore it needs to be accessible from the handler method for the save function! Add layout setting as you’re used to if you wish.

cl_salv_table=>factory(
          EXPORTING
             list_display = abap_false
           IMPORTING
             r_salv_table = o_salv
           CHANGING
             t_table      = t_data ). 

2. Optional step for custom types: Add DDIC reference for F4 generating.

DATA lt_cols      TYPE REF TO cl_salv_columns_table.
DATA ls_col_grbew TYPE REF TO cl_salv_column. 
DATA lv_grbew     TYPE lvc_fname.
DATA ls_grbew_ref TYPE salv_s_ddic_reference.
* Column name
lv_grbew = 'YY_LE_GRBEW'.
* Table name for DDIC reference
ls_grbew_ref-table = 'YMAR_CT_GRBEW'.
* Field in the above mentioned table for DDIC reference
ls_grbew_ref-field = 'YY_LE_GRBEW'. 
lt_cols = o_salv->get_columns( ).
ls_col_grbew = lt_cols->get_column(
        EXPORTING
          columnname = lv_grbew
      ).
ls_col_grbew->set_ddic_reference(
        EXPORTING
          value = ls_grbew_ref
     ). 

3. After the creation of the instance, add buttons for custom functions (like EDIT and SAVE) to the CL_SALV_TABLE instance and bind the custom event handler.

DATA GR_SALV_FUNC type ref to CL_SALV_FUNCTIONS . 
gr_salv_func = o_salv->get_functions( ).
gr_salv_func->set_all( abap_true ). 
* Add EDIT function
gr_salv_func->add_function(
            name = 'YE_QM_NOTE'
* Optionally add custom text and tooltip
            text = lv_edit_text     
            tooltip = lv_edit_tip
            position = if_salv_c_function_position=>right_of_salv_functions ). 
* Add SAVE function
gr_salv_func->add_function(
            name = 'YE_QM_SAVE'
* Optionally add custom text and tooltip
            text = lv_save_text
            tooltip = lv_save_tip
            position = if_salv_c_function_position=>right_of_salv_functions ). 
* Add custom handler method to the table (implementation details follows in the next step)
DATA(lo_events_1) = o_salv->get_event( ). 
SET HANDLER alv_1_on_added_function FOR lo_events_1. 
* Display the ALV
o_salv->display( ).
4. Add handler method for added functions (in my case, every ALV is an instance of a class, therefore the handler methods are set as instance methods). The handler method has the following signature:

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP ABAP Tutorial and Materials, SAP ABAP Guides

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP ABAP Tutorial and Materials, SAP ABAP Guides

And the implementation may look similar to this:

METHOD alv_1_on_added_function.
*>------------------------------------------
   DATA:ls_api   TYPE REF TO if_salv_gui_om_extend_grid_api,
        ls_edit  TYPE REF TO if_salv_gui_om_edit_restricted,
        lv_grbew TYPE lvc_fname,
        lv_note  TYPE lvc_fname.
* ----------------------
  lv_grbew = 'YY_LE_GRBEW'.
  lv_note = 'YY_QM_NOTE'.
  ls_api = gr_salv_1->extended_grid_api( ).
  ls_edit = ls_api->editable_restricted( ).
  CASE e_salv_function.
* Note that the cases correspond to the names of the functions we added in step 3)
    WHEN 'YE_QM_NOTE'.
* Code for edit enabling goes here - implementation follows in step 5)
    WHEN 'YE_QM_SAVE'.
* Code for save goes here - implementation follows in step 6)
          WHEN OTHERS.
* Do nothing
  ENDCASE.
ENDMETHOD. 

5. Implementation of the EDIT case – turned on or off for given columns. The instance of the ALV has an attribute signalling whether or not editing is currently on.
IF gv_edit = ''.
        gv_edit = 'X'.
      ELSE.
        gv_edit = ''.
      ENDIF.
      IF gv_edit = 'X'.
        TRY.
* Enable editing
            ls_edit->set_attributes_for_columnname(
            EXPORTING
              columnname = lv_grbew
              all_cells_input_enabled = abap_true
            ).
            ls_edit->set_attributes_for_columnname(
            EXPORTING
              columnname = lv_note
              all_cells_input_enabled = abap_true
            ).
          CATCH cx_salv_not_found.
        ENDTRY.
      ELSE.
        TRY.
* Disable editing
            ls_edit->set_attributes_for_columnname(
              EXPORTING
                columnname = lv_grbew
                all_cells_input_enabled = abap_false
              ).
            ls_edit->set_attributes_for_columnname(
            EXPORTING
              columnname = lv_note
              all_cells_input_enabled = abap_false
            ).
          CATCH cx_salv_not_found.
        ENDTRY.
* When editing is turned off, the user input is checked and data table updated
        ls_edit->validate_changed_data(
      ).
        o_salv->refresh( ).
      ENDIF.

6. Implementation of the SAVE case

TRY.
    ls_edit->validate_changed_data(
          IMPORTING
            is_input_data_valid = DATA(s)
          ).
          o_salv->refresh( ).
        CATCH cx_salv_not_found.
ENDTRY.
* Input is valid, we can save the data
      IF s = 'X'.
* You will need to implement your own save method, based on your own data
            save( ).
       ENDIF.
And this is it! The removal of inheritance from CL_SALV_TABLE may have broken one method of enabling editing, but fortunately another one was made possible. Once again, this is only possible from release 756 onwards. The previous releases still contain the inheritance and therefore editing can be done by the method described in the method linked at the beginning.

No comments:

Post a Comment