I have ALV table and I made a custom button in the table toolbar. Whenever the button is pressed, I want to delete the selected row. Now there's just a message showing up so I could see if the custom button is working.
METHOD on_user_command.
CASE e_salv_function.
WHEN 'MYFUNC1'.
MESSAGE i301(z_global) WITH 'Function 1'.
*Right here the row should be deleted.
WHEN 'MYFUNC2'.
MESSAGE i301(z_global) WITH 'Function 2'.
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
Here is the sample code for deleting selected row:
CASE e_salv_function.
WHEN 'MYFUNC1'.
PERFORM delete_lines.
...
ENDCASE.
form delete_lines.
data: sav_tabix type lvc_index.
clear row_table.
call method grid1->get_selected_rows( et_index_rows = data(row_table) ).
loop at gt_outtab.
sav_tabix = sav_tabix + 1.
read table row_table with key index = sav_tabix.
if sy-subrc = 0.
delete gt_outtab INDEX sav_tabix.
endif.
endloop.
call method grid1->refresh_table_display.
call method cl_gui_cfw=>flush.
endform.
Related
I am struggling with the following issue:
I have two tables (header and items) that I want to connect them by using a hotspot and the class CL_SALV_TABLE. I managed to display the header table and set a hotspot on the column with the number of the order. I want that the second table opens as a popup window after I click once on the number field (which was my hotspot). However, I don't know how to define the event. I know how to get a popup window by using the display method of CL_SALV_TABLE, e.g., this code:
CALL METHOD cl_salv_table=>factory(
* EXPORTING
* list_display = IF_SALV_C_BOOL_SAP=>FALSE
* r_container =
* container_name =
IMPORTING
r_salv_table = o_alv
CHANGING
t_table = it_tab )
.
CATCH cx_salv_msg .
ENDTRY.
o_alv->set_screen_popup( start_column = 1
end_column = 150
start_line = 1
end_line = 30 ).
o_alv->display( ).
Any comment or help is highly appreciated. Thank you in advance!
Here is a minimal example to execute code when an ALV hotspot field is clicked (when any cell in the column "Book number" is clicked, a popup is displayed with a text, but you can do whatever you want of course).
What is important to remember:
METHODS on_hotspot_click FOR EVENT hotspot_click OF cl_gui_alv_grid ... : this is the method to define the code to run when the hotspot field is clicked
SET HANDLER on_hotspot_click ... : to tell the Control Framework to trigger the method when the event occurs
Code:
CLASS lcl_app DEFINITION.
PUBLIC SECTION.
METHODS constructor.
METHODS on_hotspot_click
FOR EVENT hotspot_click OF cl_gui_alv_grid
IMPORTING e_row_id e_column_id es_row_no.
DATA go_alv TYPE REF TO cl_gui_alv_grid.
DATA gt_sbook TYPE TABLE OF sbook.
ENDCLASS.
CLASS lcl_app IMPLEMENTATION.
METHOD constructor.
CREATE OBJECT go_alv EXPORTING i_parent = cl_gui_container=>screen0.
SELECT * FROM sbook INTO TABLE gt_sbook.
DATA(fieldcatalog) = VALUE lvc_t_fcat(
( fieldname = 'BOOKID' ref_table = 'SBOOK' ref_field = 'BOOKID' hotspot = 'X' ) ).
SET HANDLER on_hotspot_click FOR go_alv.
go_alv->set_table_for_first_display(
EXPORTING i_structure_name = 'SBOOK'
CHANGING it_outtab = gt_sbook it_fieldcatalog = fieldcatalog ).
ENDMETHOD.
METHOD on_hotspot_click.
READ TABLE gt_sbook INDEX es_row_no-row_id INTO DATA(ls_sbook).
IF sy-subrc = 0.
MESSAGE |click { ls_sbook-bookid } col { e_column_id-fieldname } row { es_row_no-row_id }| TYPE 'I'.
ENDIF.
ENDMETHOD.
ENDCLASS.
DATA go_app TYPE REF TO lcl_app.
PARAMETERS dummy.
AT SELECTION-SCREEN OUTPUT.
IF go_app IS NOT BOUND.
go_app = NEW lcl_app( ).
ENDIF.
I am trying to toggle(hide) the selection screens based on radio button input. But the code seems not working.
" Radio button block
SELECTION-SCREEN BEGIN OF BLOCK search_block WITH FRAME TITLE text-001.
PARAMETER: rad_flt RADIOBUTTON GROUP rgb DEFAULT 'X',
rad_cus RADIOBUTTON GROUP rgb.
SELECTION-SCREEN END OF BLOCK search_block.
" Selection screen 1
SELECTION-SCREEN BEGIN OF BLOCK flight_block WITH FRAME TITLE text-002.
PARAMETER: carrid TYPE sbook-carrid,
connid TYPE sbook-connid,
fldate TYPE sbook-fldate MODIF ID sc1.
SELECTION-SCREEN END OF BLOCK flight_block.
" Selection screen 2
SELECTION-SCREEN BEGIN OF BLOCK customid_block WITH FRAME TITLE text-002.
PARAMETER: customid TYPE sbook-customid MODIF ID sc2.
SELECTION-SCREEN END OF BLOCK customid_block.
AT SELECTION-SCREEN OUTPUT.
*Toggle the selection screens based on radio buttons
LOOP AT SCREEN.
IF rad_flt = 'X' AND screen-group1 = 'sc2'.
screen-active = 0.
MODIFY SCREEN.
ELSEIF rad_cus = 'X' AND screen-group1 = 'sc1'.
screen-active = 0.
MODIFY SCREEN.
ENDIF.
ENDLOOP.
The screen displays all the screens. Not able to track the issue using debugger.
By default radio buttons don't trigger any events, which is what you need to perform some actions on radio button toggle (and not on Enter press or execution). You can do it by adding user-command <eventcode> to your radio button group and then handling those events in At selection-screen output .
tables: sscrfields. "Only needed if you need to tell different events apart.
select-options:
so_1_1 for lfa1-lifnr modif id g1,
so_1_2 for lfa1-kunnr modif id g1,
so_2_1 for kna1-lifnr modif id g2,
so_2_2 for kna1-kunnr modif id g2,
parameters:
p_1 radiobutton group prct user-command rb_prct default 'X',
p_2 radiobutton group prct,
p_3 radiobutton group prct.
at selection-screen.
lv_ucomm = sscrfields-ucomm. "only needed if you need to tell different events apart.
At selection-screen output.
"In here you can check if lv_ucomm = 'RB_PRCT' before doing anything
case abap_true.
when p_1.
lv_group = 'G1'.
when p_2.
lv_group = 'G2'.
when p_3.
lv_grou = ' '.
endcase.
loop at screen.
screen-active = boolc( screen-group1 is initial or screen-group1 = lv_group )
modify screen.
endloop.
Something like this will fit your needs, but if you need more processing on radio button press (and not to anything on other actions) you might want to use the SSCRFIELDS related logic to check which event is fired and only process the one that comes from your radio buttons.
i have created a bobf object in cds named /BOBF/IF_FRW_VALIDATION~EXECUTE
to use it for validation purpose i have tried following code to stop updating the value using its export parameter eo_message.
DATA: ls_message TYPE symsg.
if lv_val = abap_false.
ls_message-msgty ='E'.
ls_message-msgid = 'SY'.
ls_message-msgno = '005'.
IF eo_message IS NOT BOUND.
eo_message = /bobf/cl_frw_factory=>get_message( ).
ENDIF.
ET_FAILED_KEY = IT_KEY.
APPEND VALUE #( key = ls_root-key ) TO et_failed_key.
CALL METHOD eo_message->add_message
EXPORTING
is_msg = ls_message.
endif.
but the update operation(for which i have created the bobf) is still being performed
in bobf validations object click on "trigger configuration" of your corresponding implementation class there i had to select on 'check before save' and also select checkbox of the check field along with update field.
Whenever an invalid value is entered in an ALV Grid, how do I disable the other fields (grey out) in the grid and force the user to fix the incorrect field.
I have tried adding protocol in DATA_CHANGED event. But protocol list only shows the error in popup. Editing is still possible and no fields are disabled.
But how do I disable the other fields. Sample behavior as shown below:
Here, the other fields are greyed out and the invalid entry is highlighted. Until the user fixes this error, he/she cannot proceed further.
Having screen 100 with container CCONTAINER1 paste this snippet
CLASS zcl_alv_test DEFINITION.
PUBLIC SECTION.
METHODS: constructor, display_grid, populate_grid.
DATA: lr_rtti_struc TYPE REF TO cl_abap_structdescr,
it_fldcat TYPE lvc_t_fcat,
grid_container1 TYPE REF TO cl_gui_custom_container,
grid1 TYPE REF TO cl_gui_alv_grid.
DATA: BEGIN OF gs_outtab.
INCLUDE TYPE spfli.
DATA: celltab TYPE lvc_t_styl.
DATA: END OF gs_outtab.
DATA gt_outtab1 LIKE TABLE OF gs_outtab INITIAL SIZE 0.
METHODS:
handle_data_changed FOR EVENT data_changed OF cl_gui_alv_grid IMPORTING er_data_changed,
handle_data_changed_finished FOR EVENT data_changed_finished OF cl_gui_alv_grid IMPORTING e_modified et_good_cells,
create_dynamic_fcat.
PRIVATE SECTION.
TYPES: ty_tab LIKE LINE OF gt_outtab1.
METHODS: refresh_grid, fill_celltab IMPORTING p_fieldname TYPE lvc_fname
CHANGING pt_celltab TYPE lvc_t_styl.
ENDCLASS.
CLASS zcl_alv_test IMPLEMENTATION.
METHOD constructor.
CREATE OBJECT grid_container1 EXPORTING container_name = 'CCONTAINER1'.
CREATE OBJECT grid1 EXPORTING i_parent = grid_container1.
SET HANDLER handle_data_changed FOR grid1.
SET HANDLER handle_data_changed_finished FOR grid1.
CALL METHOD grid1->register_edit_event
EXPORTING
i_event_id = cl_gui_alv_grid=>mc_evt_enter.
ENDMETHOD. "constructor
METHOD fill_celltab.
LOOP AT pt_celltab ASSIGNING FIELD-SYMBOL(<fs_fcat>).
IF <fs_fcat>-fieldname = p_fieldname.
<fs_fcat>-style = cl_gui_alv_grid=>mc_style_enabled.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD handle_data_changed.
DATA: lt_celltab TYPE lvc_t_styl.
LOOP AT it_fldcat ASSIGNING FIELD-SYMBOL(<fs_fcat>).
INSERT VALUE lvc_s_styl( style = cl_gui_alv_grid=>mc_style_disabled fieldname = <fs_fcat>-fieldname ) INTO TABLE lt_celltab.
ENDLOOP.
MODIFY gt_outtab1 FROM VALUE ty_tab( celltab = lt_celltab ) TRANSPORTING celltab WHERE connid IS NOT INITIAL.
LOOP AT er_data_changed->mt_mod_cells ASSIGNING FIELD-SYMBOL(<mods>).
READ TABLE gt_outtab1 ASSIGNING FIELD-SYMBOL(<sym>) INDEX <mods>-row_id.
fill_celltab( EXPORTING p_fieldname = <mods>-fieldname
CHANGING pt_celltab = <sym>-celltab ).
MODIFY gt_outtab1 FROM <sym> INDEX <mods>-row_id.
ENDLOOP.
refresh_grid( ).
ENDMETHOD.
METHOD handle_data_changed_finished.
DATA: lt_celltab TYPE lvc_t_styl.
LOOP AT it_fldcat ASSIGNING FIELD-SYMBOL(<fs_fcat>).
IF sy-tabix MOD 2 = 0.
DATA(style) = cl_gui_alv_grid=>mc_style_disabled.
ELSE.
style = cl_gui_alv_grid=>mc_style_enabled.
ENDIF.
INSERT VALUE lvc_s_styl( style = style fieldname = <fs_fcat>-fieldname ) INTO TABLE lt_celltab.
ENDLOOP.
MODIFY gt_outtab1 FROM VALUE ty_tab( celltab = lt_celltab ) TRANSPORTING celltab WHERE connid IS NOT INITIAL.
refresh_grid( ).
ENDMETHOD.
METHOD create_dynamic_fcat.
lr_rtti_struc ?= cl_abap_structdescr=>describe_by_name( 'SPFLI' ).
DATA(comps) = lr_rtti_struc->components.
LOOP AT comps ASSIGNING FIELD-SYMBOL(<comps>).
IF sy-tabix MOD 2 = 0.
DATA(edit) = abap_false.
ELSE.
edit = abap_true.
ENDIF.
APPEND VALUE lvc_s_fcat( edit = edit fieldname = <comps>-name datatype = <comps>-type_kind inttype = <comps>-type_kind intlen = <comps>-length decimals = <comps>-decimals coltext = <comps>-name lowercase = 'X' ) TO it_fldcat .
ENDLOOP.
ENDMETHOD. "create_dynamic_fcat
METHOD populate_grid.
SELECT * UP TO 1000 ROWS
FROM spfli
INTO CORRESPONDING FIELDS OF TABLE gt_outtab1.
ENDMETHOD. "CHANGE_TITLE
METHOD display_grid.
create_dynamic_fcat( ).
grid1->set_table_for_first_display(
EXPORTING
is_layout = VALUE lvc_s_layo( zebra = abap_true stylefname = 'CELLTAB' )
CHANGING
it_outtab = gt_outtab1
it_fieldcatalog = it_fldcat ).
ENDMETHOD. "display_grid
METHOD refresh_grid.
cl_gui_cfw=>flush( ).
grid1->refresh_table_display( ).
ENDMETHOD.
ENDCLASS.
MODULE status_0100 OUTPUT.
SET PF-STATUS 'MAIN100'.
DATA: yalv TYPE REF TO zcl_alv_test.
CREATE OBJECT yalv.
yalv->populate_grid( ).
yalv->display_grid( ).
ENDMODULE.
MODULE user_command_0100 INPUT.
CASE sy-ucomm.
WHEN 'BACK' OR 'EXIT' OR 'RETURN'.
LEAVE PROGRAM.
WHEN OTHERS.
ENDCASE.
ENDMODULE.
START-OF-SELECTION.
CALL SCREEN 100.
It uses the concept of cell styles, where each row in table is assigned a table of styles for each of the column in this row. There you can apply conditional attributes on a cell level, including editability.
When throwing an error through builtin checktables/domains, the grid is made not editable except erroneous cell, and when correcting the error, editability returns.
I want to access cell value in my ALV OOPS instance for a deleted row.
LOOP AT er_data_changed->mt_deleted_rows INTO ls_del.
CALL METHOD er_data_changed->get_cell_value
EXPORTING
i_row_id = ls_del-row_id
i_fieldname = 'FIPEX'
IMPORTING
e_value = lv-fipex.
ENDLOOP.
but lv-fipex is always blank. Why get_cell_value doesn't work with deleted rows? What can I use for this?
This method seems to return data only if you modify a particular cell or cells of a row. In order to achieve what you want read directly from the internal table used as CHANGING parameter in the call of method SET_TABLE_FOR_FIRST_DISPLAY. The actual deletion occurs after the event DATA_CHANGED so you can do that as the data to be deleted are still in the internal table.
Look at this example (you have to create the screen and status 100 by yourself).
REPORT ZZZ.
CLASS lcl_main DEFINITION FINAL CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS:
main,
on_data_changed FOR EVENT data_changed OF cl_gui_alv_grid
IMPORTING
er_data_changed,
on_double_click FOR EVENT double_click OF cl_gui_alv_grid
IMPORTING
es_row_no.
PRIVATE SECTION.
CLASS-DATA:
st_t000 TYPE STANDARD TABLE OF t000 WITH EMPTY KEY.
ENDCLASS.
MODULE status_0100 OUTPUT.
SET PF-STATUS '100'.
lcl_main=>main( ).
ENDMODULE.
MODULE user_command_0100 INPUT.
IF sy-ucomm = 'BACK'.
LEAVE TO SCREEN 0.
ENDIF.
ENDMODULE.
CLASS lcl_main IMPLEMENTATION.
METHOD on_double_click.
ASSERT 1 = 1.
ENDMETHOD.
METHOD on_data_changed.
DATA: l_value TYPE t000-ort01.
LOOP AT er_data_changed->mt_deleted_rows ASSIGNING FIELD-SYMBOL(<fs_deleted_row>).
* er_data_changed->get_cell_value(
* EXPORTING
* i_row_id = <fs_deleted_row>-row_id
* i_fieldname = 'ORT01'
* IMPORTING
* e_value = l_value
* ).
l_value = st_t000[ <fs_deleted_row>-row_id ]-ort01.
ENDLOOP.
ENDMETHOD.
METHOD main.
DATA(lo_gui_container) = NEW cl_gui_custom_container( container_name = 'CONTAINER' ).
DATA(lo_gui_alv_grid) = NEW cl_gui_alv_grid( i_parent = lo_gui_container ).
SELECT * FROM t000 INTO TABLE st_t000 UP TO 20 ROWS.
lo_gui_alv_grid->set_ready_for_input( 1 ).
SET HANDLER on_data_changed FOR lo_gui_alv_grid.
SET HANDLER on_double_click FOR lo_gui_alv_grid.
lo_gui_alv_grid->set_table_for_first_display(
EXPORTING
i_structure_name = 'T000'
CHANGING
it_outtab = st_t000
EXCEPTIONS
invalid_parameter_combination = 1
program_error = 2
too_many_lines = 3
OTHERS = 99
).
ASSERT sy-subrc = 0.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
CALL SCREEN 100.