ALV Tree node events are not fired - abap

I experience a problem when I use ALV Tree without item selection enabled. In this case I am not able to receive an event for node context menu request.
When I turn item selection on, everything works fine.
I get the events for the context menu request for nodes as well as items, but i don't need item selection enabled for my application.
Here is some code I can share:
DATA: g_tree TYPE REF TO cl_gui_alv_tree.
* create container for alv-tree
DATA: l_tree_container_name(30) TYPE c,
l_custom_container TYPE REF TO cl_gui_custom_container.
l_tree_container_name = 'TREE'.
CREATE OBJECT l_custom_container
EXPORTING
container_name = l_tree_container_name.
* create tree control
CREATE OBJECT g_tree
EXPORTING
parent = l_custom_container
node_selection_mode = cl_gui_column_tree=>node_sel_mode_single
item_selection = abap_true "WOULD LIKE TO HAVE THIS SET TO FALSE
no_html_header = abap_true
no_toolbar = ''.
And here I register the events:
DATA: lt_events TYPE cntl_simple_events,
l_event TYPE cntl_simple_event.
l_event-eventid = cl_gui_column_tree=>eventid_node_context_menu_req.
APPEND l_event TO lt_events.
l_event-eventid = cl_gui_column_tree=>eventid_item_context_menu_req.
APPEND l_event TO lt_events.
CALL METHOD g_tree->set_registered_events
EXPORTING
events = lt_events
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
illegal_event_combination = 3.
DATA: l_event_receiver TYPE REF TO tree_event_receiver.
CREATE OBJECT l_event_receiver.
SET HANDLER l_event_receiver->handle_node_ctmenu_request FOR g_tree.
SET HANDLER l_event_receiver->handle_node_ctmenu_selected FOR g_tree.
SET HANDLER l_event_receiver->handle_item_ctmenu_request FOR g_tree.
SET HANDLER l_event_receiver->handle_item_ctmenu_selected FOR g_tree.
And here are my handlers:
METHOD handle_node_ctmenu_request.
CALL METHOD menu->add_function
EXPORTING
fcode = 'DELETE_ITEM'
text = 'delete'.
ENDMETHOD.
METHOD handle_item_ctmenu_request.
CALL METHOD menu->add_function
EXPORTING
fcode = 'DELETE_ITEM'
text = 'delete'.
ENDMETHOD.
So both methods are working when item_selection is set to true. Neither of them is working, when item_selection is set to false. However, I would have expected the handle_node_ctmenu_request would be fired in this case.

The trick is in the interconnection of different types of events in ALV Tree Model.
Official SAP Control Framework documentation states that:
If you set the parameter item_selection = 'X' when you created the
instance, you can also react to the following events:
...
ITEM_CONTEXT_MENU_REQUEST
ITEM_CONTEXT_MENU_SELECT
...
But, unfortunately, it doesn't state (it is implied, like many else in SAP world) that Control Framework treats item and node events in pool.
So, if you register item-related events with disabled item_selection parameter, the node-related events will not work as well.
In other words, do not register item-related events, if you want to achieve reaction to your node-related events, or set this parameter to "Enabled".

Related

ABAP report toolbar is disabled

I'm having trouble making the Toolbar(see image) of my SAP Report working despite having tried multiple solutions.
My report's code:
CLASS cl_orders_alv DEFINITION.
PUBLIC SECTION.
METHODS:
on_init, on_display.
PRIVATE SECTION.
METHODS:
on_data_fetch.
DATA: ct_orders TYPE TABLE OF zordhead_str, " header itab
ct_orders_pos TYPE TABLE OF zordpos_str, " pos itab
co_orders_alvgrid TYPE REF TO cl_gui_alv_grid, " ALV Table
co_ordpos_alvgrid TYPE REF TO cl_gui_alv_grid, " ALV Table
co_orders_alvccntr TYPE REF TO cl_gui_custom_container, " Orders Head
co_ordpos_alvccntr TYPE REF TO cl_gui_custom_container, " Orders Position
cs_orders TYPE zordhead_str, " header structure
cs_orders_pos TYPE zordpos_str,
cs_orders_fieldcat TYPE slis_fieldcat_alv, " ALV Structure
ct_orders_fieldcat TYPE lvc_t_fcat, " ALV Table
cs_ordpos_fieldcat TYPE slis_fieldcat_alv,
ct_ordpos_fieldcat TYPE lvc_t_fcat.
ENDCLASS. "cl_orders_alv
CLASS cl_orders_alv IMPLEMENTATION.
METHOD on_init.
CLEAR ct_orders.
CLEAR ct_orders_pos.
CLEAR cs_orders.
CLEAR cs_orders_pos.
CREATE OBJECT co_orders_alvccntr
EXPORTING
container_name = 'ALV_CCONTAINER0'.
CREATE OBJECT co_ordpos_alvccntr
EXPORTING
container_name = 'ALV_CCONTAINER1'.
CREATE OBJECT co_orders_alvgrid
EXPORTING
i_parent = co_orders_alvccntr.
CREATE OBJECT co_ordpos_alvgrid
EXPORTING
i_parent = co_ordpos_alvccntr.
on_data_fetch( ).
ENDMETHOD. "on_init
METHOD on_display.
CALL METHOD co_orders_alvgrid->set_table_for_first_display
EXPORTING
i_structure_name = 'ZORDHEAD_STR'
CHANGING
it_outtab = ct_orders.
CALL METHOD co_ordpos_alvgrid->set_table_for_first_display
EXPORTING
i_structure_name = 'ZORDPOS_STR'
CHANGING
it_outtab = ct_orders_pos.
CALL SCREEN '0100'.
ENDMETHOD. "on_display
METHOD on_data_fetch.
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = 'ZORDHEAD_STR'
CHANGING
ct_fieldcat = ct_orders_fieldcat
EXCEPTIONS
inconsistent_interface = 1
program_error = 2
OTHERS = 3.
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = 'ZORDPOS_STR'
CHANGING
ct_fieldcat = ct_ordpos_fieldcat
EXCEPTIONS
inconsistent_interface = 1
program_error = 2
OTHERS = 3.
ENDMETHOD. "on_data_fetch
ENDCLASS. "CL_ORDERS_ALV IMPLEMENTATION
START-OF-SELECTION.
SET PF-STATUS 'STANDARD_FULLSCREEN'.
DATA: go_alv_gui TYPE REF TO cl_orders_alv.
CREATE OBJECT go_alv_gui.
go_alv_gui->on_init( ).
go_alv_gui->on_display( ).
This is what I have tried so far:
Copied an existing Status into my Program/Report:
Go to Transaction SE41
User Interface => Copy => Status...
From: Program= SAPLSLVC_FULLSCREEN ; Status=STANDARD_FULLSCREEN
To: Program = ZESXDV ; Status = STANDARD_FULLSCREEN
Hit Ok.
Go to Transaction SE80 and open up your Report/Program
The GUI Status folder is created, inside of which there's the new copied status.
Added the following instruction in the report's code(after START-OF-SELECTION):
SET PF-STATUS 'STANDARD_FULLSCREEN'.
Note: I noticed that the Toolbar doesn't work only when working with ALV tables and custom ALV Containers(which both needs a Screen Object[which is called by the CALL SCREEN 'XXXX' instruction.])
Am I missing something?
Thanks in advance for your help.
P.S.: If some info are missing let me know and I'll add them as soon as possible.
You must use screen code as below
PROCESS BEFORE OUTPUT.
MODULE PBO_100.
*
PROCESS AFTER INPUT.
MODULE PAI_100.
creating perform module and put your into pf-status
MODULE pbo_100 OUTPUT.
SET PF-STATUS 'MAIN100'.
set titlebar 'MAIN100'.
ENDMODULE. " PBO_100 OUTPUT
Note: check activeted gui status "MAIN100"
Thanks to #Mustafa Hamit. I'll post what I've done baesd on #Mustafa Hamit's comment.
Go to the Screen object(Double click on CALL SCREEN 100).
Navigate to tab Flow Logic.
Insert MODULE PBO_100. right after PROCESS BEFORE OUTPUT..
Insert MODULE PAI_100. right after PROCESS AFTER INPUT..
Double click on PBO_100 -> Create Object
On the PBO_100 screen write SET PF-STATUS '{NAME OF THE STATUS}' between MODULE pbo_100 OUTPUT. and ENDMODULE.
Go back and create the PAI_100 object(double click on it).
Activate everything.
Two INCLUDE statements should appear on your report's code at the end of the program.
The Toolbar should now be enabled and functional.

How to force load and item by key in form?

The case
1 - I have an accordion widget with datasource Tasks.
2. - I have a form to display info on a selected Task. It has a datasource TaskByKey.
The sought solution:
There is a button on both Tasks AccordionRow.
onClick the button should, based on the Key of the item of the AccordionRow load its data in the form with datasource TaskByKey.
What I tried:
I tried implementing the solution given as an example in Google's template, Project Tracker:
/**
* Navigates user to the specific project view page.
* #param {!string} projectKey - project key to view.
* #param {boolean=} forceReplace - optional flag that forces to replace URL
* state in cases when state push would be normally used.
*/
function gotoViewProjectPageByKey(projectKey, forceReplace) {
var params = {
projectKey: projectKey
};
gotoViewProjectPageByParams(params, forceReplace);
}
Of course the above example targets a page, where as I want to change the datasource of an element on the same page.
TLDR
How can I set the onClick event of a button to load an item by key from datasource_X to datasource_X_byKey?
Considering the fact that your TaskByKey pretends to filter only a specific task... you can put the following on the onClick event of the button.
var taskKey = widget.datasource.item._key;
var ds = app.datasources.TaskByKey;
ds.query.filters._key._equals = taskKey;
ds.load();
//Then, here you either navigate to a page or open a dialog or open a popup.
The above will work considering that your Tasks datasource and your TaskByKey datasource come from the same model.
Reference: https://developers.google.com/appmaker/scripting/api/client#Query

How to call popup window from component controller and handle subscribe_to_button_event in WDA

I found this issue in some scenario, and that is how I've resolve.
Scenario. Call a Popup window from the component-controller not from a the view.
METHOD wddoinit.
DATA: lo_popup_window TYPE REF TO if_wd_window,
lo_window_manager TYPE REF TO if_wd_window_manager,
lo_cmp_api TYPE REF TO if_wd_component,
lt_text TYPE string_table,
ls_text TYPE string.
lo_cmp_api = wd_this->wd_get_api( ).
lo_window_manager = lo_cmp_api->get_window_manager( ).
ls_text = 'Do you want to continue?'.
INSERT ls_text INTO TABLE lt_text.
CALL METHOD lo_window_manager->create_popup_to_confirm
EXPORTING
text = lt_text
button_kind = if_wd_window=>co_buttons_yesno
default_button = if_wd_window=>co_button_no
window_title = 'Information'
close_button = abap_false
RECEIVING
result = lo_popup_window.
CALL METHOD lo_popup_window->popup_to_confirm->subscribe_to_button_event
EXPORTING
controller = lo_cmp_api
button = if_wd_window=>co_button_no
handler_name = 'ACTION_BTN_NO'.
CALL METHOD lo_popup_window->popup_to_confirm->subscribe_to_button_event
EXPORTING
controller = lo_cmp_api
button = if_wd_window=>co_button_yes
handler_name = 'ACTION_BTN_YES'.
lo_popup_window->open( ).
ENDMETHOD.
-----------------------------------------------------------------------------------
In the methods set the event handlers as follow.
-----------------------------------------------------------------------------------
When I run the program
Following steps will assist you.
Create method popup_window inside component controller having method paramter
ir_vc type ref to if_wd_view_controller
Write above code in the question inside method popup_window.
add below code inside view where you want to call popup.
Code in view:
DATA lo_componentcontroller TYPE REF TO ig_componentcontroller .
lo_componentcontroller = wd_this->get_componentcontroller_ctr( ).
lo_componentcontroller->call_popup( ir_vc = lo_api_main ).
regards,
Umar Abdullah

Custom button in application toolbar of cl_salv_table?

I am making a report by using cl_salv_table, and I want to make a button on toolbar of the ALV grid which will show a predefined popup.
I was able to make a button on the toolbar and set the "Functional code" as details, and I saw in the debug mode that on clicking the button the "sy-ucomm" is set to details but it is not going the case loop.
Any help or suggestion would be appreciated.
Please look at the program SALV_DEMO_TABLE_SELECTIONS how to implement event handlers correctly, basically method on_user_command in the class lcl_handle_events is what your looking for.
First of all you should have SALV grid on a screen with container:
try.
cl_salv_table=>factory(
exporting
r_container = gr_container
container_name = 'CONTAINER'
importing
r_salv_table = gr_table
changing
t_table = gt_outtab ).
catch cx_salv_msg. "#EC NO_HANDLER
endtry.
Then all functions should be enabled:
lr_functions = gr_table->get_functions( ).
lr_functions->set_all( gc_true ).
Finally you add own function like this:
include <icon>.
try.
lr_functions->add_function(
name = 'MYFUNCTION'
icon = CONV string( icon_complete )
text = `My function`
tooltip = `My custom function`
position = if_salv_c_function_position=>right_of_salv_functions ).
catch cx_salv_existing cx_salv_wrong_call.
endtry.
The next significant step is to create on_user_command event handler either in the same class or in separate handler class:
data: gr_events type ref to lcl_handle_events.
set handler gr_events->on_user_command for lr_events.
The final thing is the handler method implementation which will do actual function work
class lcl_handle_events implementation.
method on_user_command.
message |Function { e_salv_function } is fired| TYPE 'I'.
endmethod.
endclass.

ALV is not refreshed after edit. Why?

I know my problem has been asked hundred times.
But I still cannot find any suitable solution for me
I have a dropdown, every time I change data in dropdown it will load new data based on dropdown data
From step one, I refresh editable ALV
Any change in editable ALV willbe saved (another action for saving)
My problem if, After I save, I can't refresh my ALV.
But it's not problem if I haven't pressed save button
NOTE :
in SAP forum, they told me to move refresh function to PBO, I tried this but still failed.
Attached Code is Step 1 is "when SET_P" in this code
PBO
MODULE pbo_1000 OUTPUT.
IF flag = 0.
SET PF-STATUS '1000'.
SET TITLEBAR '1000'.
PERFORM create_toolbar.
PERFORM create_catalog.
PERFORM select_data.
CREATE OBJECT ob_custom
EXPORTING
container_name = 'CCTRL'.
CREATE OBJECT ob_grid
EXPORTING
i_parent = ob_custom
i_appl_events = 'X'.
PERFORM create_dropbox.
CALL METHOD ob_grid->set_table_for_first_display
EXPORTING
i_structure_name = 'TYPE'
it_toolbar_excluding = lt_toolbar
is_layout = lyt
CHANGING
it_fieldcatalog = fld[]
it_outtab = itab[].
CALL METHOD ob_grid->set_ready_for_input
EXPORTING
i_ready_for_input = 1.
CALL METHOD ob_grid->register_edit_event
EXPORTING
i_event_id = cl_gui_alv_grid=>mc_evt_enter.
ENDIF.
ENDMODULE.
PAI
MODULE user_command_1000 INPUT .
DATA: v_perio(6) TYPE c.
CASE sy-ucomm.
WHEN 'BACK' OR 'EXIT' OR 'CANCEL'.
LEAVE TO SCREEN 0.
WHEN 'SAVE'.
PERFORM save_data.
PERFORM send_email.
WHEN 'SET_S'.
flag = 1.
PERFORM set_status.
CALL METHOD ob_grid->refresh_table_display
EXPORTING
is_stable = stbl.
WHEN 'SET_P'.
flag = 1.
PERFORM select_data.
CALL METHOD ob_grid->refresh_table_display
EXPORTING
is_stable = stbl.
ENDCASE.
ENDMODULE.
I guess you will need the CHECK_CHANGED_DATA method called as first thing in the PAI, which would fire up the events DATA_CHANGED and DATA_CHANGED_FINISHED.
But most important thing is, that it will synchronize the OLE object with the instance backend and then when you are calling the REFRESH_TABLE_DISPLAY it would refresh your ALV properly. I don't have any example at the moment, but I can maybe try next week when I have access to system.
By the way in PBO you don't need to have the variable flag you can use check if the ALV object has been already initialized or not and according to this you can create/refresh alv. Something like this:
if alvGridRef is NOT bound .
data(container) = new cl_gui_custom_container( ) .
data(alvGridRef) = new cl_gui_alv_grid( ) .
else .
alvGridRef->refresh_table_display( ) .
endif .
I've done something similar in an application that needed to be refreshed when saved because some calculations had to change in the screen. I set part of the following code in the command form for the 'REUSE_ALV_GRID_DISPLAY' function module.
form user_command using r_ucomm like sy-ucomm
rs_selfield type slis_selfield.
data: ref_grid type ref to cl_gui_alv_grid, l_valid type c.
if ref_grid is initial.
call function 'GET_GLOBALS_FROM_SLVC_FULLSCR'
importing
e_grid = ref_grid.
endif.
if not ref_grid is initial.
call method ref_grid->check_changed_data
importing
e_valid = l_valid.
endif.
rs_selfield-refresh = 'X'.
...
if not ref_grid is initial.
call method ref_grid->refresh_table_display( ) .
endif.
endform.
Hope it helps
You might achieve this by manually triggering PBO. You stated that the Editing is saved, so you can just display the ALV in PBO again:
CALL FUNCTION 'SAPGUI_SET_FUNCTIONCODE'
EXPORTING
functioncode = 'REFRESH'
EXCEPTIONS
function_not_supported = 1
OTHERS = 2.
After this action, sy-ucomm in PBO has the value REFRESH.