I have an instance of CL_GUI_ALV_GRID referenced by variable mo_alv_grid.
I have a button column in this grid, which after some logic, updates the table mt_alv_grid (backing mo_alv_grid).
I need to be able to trigger the event DATA_CHANGED at this point.
I have tried many methods of CL_GUI_ALV_GRID, like CHECK_DATA_CHANGED and REFRESH_TABLE_DISPLAY
and even CL_GUI_CFW=>FLUSH and CL_GUI_CFW=>SET_NEW_OK_CODE( 'ENTER' ). but none of this has worked.
Is there a way to trigger the DATA_CHANGED event, or should I be doing things completely differently ?
I don't know if this solves your problem, but in order to update the ALV internal table in the PAI, you could use the following method:
DATA lv_entries_are_consisted TYPE abap_bool.
mo_grid->check_changed_data(
IMPORTING
e_valid = lv_entries_are_consisted
).
well, it's possible.
1) don't change values in internal table by program
2) create a change protocol of type LVC_T_MODI with a new values for lines needed
then call
CALL METHOD lo_grid->change_data_from_inside
EXPORTING
it_style_cells = lt_cells.
where lo_grid is instance of cl_gui_alv_grid and lt_cells table type LVC_T_MODI. please note, that you will need to set field VAL_DATA of layout structure (LVC_S_LAYO) to 'X' when calling ALV grid for the first time to make this work.
after this, class will automatically change internal table for you and call DATA_CHANGE event
Related
I have an ALV grid with an editable field, if I check the data entered and display errors, the ALV updates, if I try to change the input data, other times the ALV does not update anymore.
The code in the PAI is:
ls_layout-cwidth_opt = abap_true.
CREATE OBJECT go_alv
EXPORTING
i_parent = cl_gui_custom_container=>screen0
EXCEPTIONS
error_cntl_create = 1
error_cntl_init = 2
error_cntl_link = 3
error_dp_create = 4
OTHERS = 5.
IF sy-subrc EQ 0.
* Adapting field catalog
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = 'ZAMOUNT'
CHANGING
ct_fieldcat = lt_fieldcat.
IF sy-subrc EQ 0.
* Field catalog specifics
LOOP AT lt_fieldcat ASSIGNING <ls_fieldcat>.
IF <ls_fieldcat>-fieldname = 'DMBTR'.
<ls_fieldcat>-edit = abap_true.
ENDIF.
ENDLOOP.
ENDIF.
* Show data usig ALV class
go_alv->set_table_for_first_display(
EXPORTING
is_layout = ls_layout
CHANGING
it_outtab = gt_out
it_fieldcatalog = lt_fieldcat ).
go_alv->set_ready_for_input( EXPORTING
i_ready_for_input = 1 ).
CALL METHOD go_alv->register_edit_event
EXPORTING
i_event_id = cl_gui_alv_grid=>mc_evt_enter.
CALL METHOD go_alv->register_edit_event
EXPORTING
i_event_id = cl_gui_alv_grid=>mc_evt_modified.
ENDIF.
The code in the PBO is:
IF go_alv IS NOT INITIAL.
CALL METHOD go_alv->check_changed_data( ).
PERFORM check_amounts TABLES gt_out
CHANGING gv_sum_amounts
gv_tot_amount.
CALL METHOD go_alv->refresh_table_display
EXPORTING
is_stable = VALUE #( row = abap_true
col = abap_true )
i_soft_refresh = 'X'.
cl_gui_cfw=>flush( ).
ENDIF.
In the perform check_amounts I populate a field of the ALV with the errors, if the user modifies the input field and the error is removed in the internal table but it is not shown in the ALV.
I also tried to implement the data_change_finished method by calling the refresh inside but I have not solved the anomaly.
Can you help me?
Thanks
I'm not quite sure if I understand your problem but here are some potential issues I see:
You have your validity checks split up. On the one hand there is the data_changed event. On the other hand you have the check_amounts perform.
If the data_changed event finds an input error, it'll show you the red outline on your grid. In your internal table ("gt_out") this field will stay the same as before (it'll not update the table with the invalid input !).
This might be why you think there should be a message in your grid but there isn't.
Did you define your own local version for the data_changed event? Than the handlers are missing. When you tried doing the refresh in the data_changed_finished event you definitly need the handler for that.
Also you said that you only put the refresh in the method for data_changed_finished. You need to put the check_amount perform there too then. Otherwise you called the refresh to early.
In the method for data_changed_finished you have the automatically updated table ("gt_out") from the data_changed method. You should be able to update it here and send it to your grid with a refresh.
I don't like that you call the check_changed_data method in your PBO. Because of the register_edit_event calls the data_changed event already triggers when you hit enter or jump to the next field. You usually only call this method when you received a seperat user command, that can be fired before the event can be triggered to be sure that you have correct data.
Not 100% sure about this but for your register_edit_event calls, the event id cl_gui_alv_grid=>mc_evt_modified should include the event id cl_gui_alv_grid=>mc_evt_enter already.
I'd try to define a local class to handle the data_changed and data_changed_finished events and put the check_amount and refresh in the method for the data_changed_finished event.
Maybe some of this helps you? If you have any questions about any of this, let me know and I can go into more detail.
regards
I am trying to display updated records in ALV but old records are being displayd.
Here is the code written in the screen exit of work order.
TRY.
cl_salv_table=>factory(
EXPORTING
r_container = lo_cust_container
IMPORTING
r_salv_table = lo_alv_table
CHANGING
t_table = gt_wflog ).
**// Functions
DATA(lo_alv_functions) = lo_alv_table->get_functions( ).
lo_alv_functions->set_all( abap_true ).
**// Display Settings
DATA(lo_alv_display) = lo_alv_table->get_display_settings( ).
lo_alv_display->set_striped_pattern( abap_true ).
**// Layout Settings
DATA: ls_layout_key TYPE salv_s_layout_key.
DATA(lo_alv_layout) = lo_alv_table->get_layout( ).
ls_layout_key-report = sy-repid.
lo_alv_layout->set_key( ls_layout_key ).
lo_alv_layout->set_save_restriction( cl_salv_layout=>restrict_user_independant ).
lo_alv_columns->set_optimize( abap_true ).
lo_alv_table->set_data( CHANGING t_table = gt_wflog[] ).
lo_alv_table->display( ).
CATCH cx_salv_msg cx_salv_error INTO DATA(lx_salv_msg).
MESSAGE lx_salv_msg->get_text( ) TYPE 'I'.
ENDTRY.
I tried to used method refresh lo_alv_table->resfresh( ). with option soft or full refresh but nothing happened. First time call data is ok when subscreen is called again and there is change in data then updated records are not displayed. I can see updated records in the table during debug.
More than likely you have CX_SALV_NO_NEW_DATA_ALLOWED exception which is caught by TRY clause during the second call of your instantiation. That's why display() method is not executed.
There is a note in SET_DATA method documentation:
You are not able to call these methods in an event handler. If you
do you will get an error.
...
Exceptions
CX_SALV_NO_NEW_DATA_ALLOWED
You have called SET_DATA in an event handler.
In your context screen exit is the same as event handler as it is called by the same event.
Solution is confirmed by OP: "It works perfectly"
Added to declarations in the top include.
DATA go_alv_table TYPE REF TO cl_salv_table.
Added in the code
IF go_alv_table IS NOT BOUND.
cl_salv_table=>factory( )
...
ENDIF.
Added after set_data method call
go_alv_table->refresh( refresh_mode = if_salv_c_refresh=>soft ).
That's a well-known issue with controls. If you instantiate any GUI control (in your case, it's the ALV grid) inside a container in which there was already a control which has not been freed up (in your case, the ALV grid first instantiated using cl_salv_table=>factory), then the old control still shows up, the new one is not shown.
Two solutions :
Either you keep instantiating the control, but then you must free the previous control. For this, you must call control->FREE( ) followed by the statement FREE control. This method is available for all controls (even the container itself can be freed, all its inner controls are then freed up).
Or you change the logic by instantiating the control only once, and you refresh its contents.
Special case: some controls may be wrapped by some wrapper classes which don't give access to the control (SALV classes for instance), so the easy way is to free the container to which the control is attached.
Just an addition to #suncatcher's answer.
Firstly checks whether a reference variable contains a valid reference: 'IF go_alv_grid IS BOUND'.
Example:
SELECT * FROM zemployees BYPASSING BUFFER INTO TABLE it_zemployees.
IF go_alv_grid IS BOUND.
go_alv_grid->refresh( ).
ELSE.
cl_salv_table=>factory(
EXPORTING
r_container = NEW cl_gui_custom_container( 'CONTAINER_NAME' )
container_name = 'CONTAINER_NAME'
IMPORTING
r_salv_table = go_alv_grid
CHANGING
t_table = it_zemployees
).
"Style the table
go_alv_grid->get_functions( )->set_all( ).
go_alv_grid->get_columns( )->set_optimize( ).
go_alv_grid->get_display_settings( )->set_striped_pattern( abap_true ).
go_alv_grid->display( ).
ENDIF.
I was using Event aggregate publish method to update view from another view. when I created publish and subscribe data was able to get in view model , but that is not updating in view with assigned variables. If I use JavaScript to fill value it's working but not able to trigger validate controller.
Expected result is:
From the subscribe method I have to fill the view values.
After that it should trigger validate on value changes.
In below gist run I have two view and view-model. One is registration-form and second one is data-form. In data-form I have table with data, on click of each row I am publishing one event with selected row data, and this published event I was subscribing in side of registration-form view-modal. For more details look into below gist run.
Gist run: https://gist.run/?id=8416e8ca1b9b5ff318b79ec94fd3220c
Two possible solutions: (to your "undefined" alert)
Change alert(this.email); to alert(myself.email);
Use the thick arrow syntax for the subscribe function. Change:
this.ea.subscribe('MyrowData', function(obj){
to
this.ea.subscribe('MyrowData', obj => {
This syntax allows the new function to preserve the context/scope of the parent, which means that this.email will still be accessible.
Another suggestion:
You could simplify your data-form.js function as follows:
Change:
this.eventAggregator.publish('MyrowData', this.items[this.items.indexOf(item)]);
to:
this.eventAggregator.publish('MyrowData', item);
This will work because you've already provided item in your function call click.delegate="PopulateData(item, $event)".
In fact, you could even delete $event and event from the two PopulateData definitions (in data-form.js and data-form.html).
When I implement these suggestions, your data is also validated correctly.
I would like to update form fields "on-fly" after button press that triggers python function.
Something like onchange that allows to return field values, but I need to do it after button press.
The situation is, to create module, that will allow to search for company information in public company register based on entered company registration ID.
The best would be, to show up some popup window with updated fields list and user has to confirm, wether to update fields values or not.
Thank you.
You can create a wizard (osv.osv_memory class) to simulate a dynamic popup window.
To populate this wizard, you can use the returned action descriptor of your python function, like this :
return {'res_model':'your.osv.memory',
'view_mode':'form',
'view_type':'form',
'target':'new',
'context':{...},
}
Thanks to your algorythm that get public company information, you just have to put you're fields values on the context, like you would do in a write() method.
Override your default_get() method of your osv_memory, which receives your context, and populate your wizard like you want.
I think a simple text fields on your wizard will be efficient to display fields updated values, and 2 buttons : cancel and OK (which will call the write method to apply fields values, always using your context).
I have window that contains a table on screen, now I want to attach a widget to that table I use
gtk_table_attach(GTK_TABLE(table), label, ...)
the function is correct and it runs without any error
but table does not respond to that line I mean there is no change on my table, I think I need something to tell that table update it self but how?
note= that line is inside a callback of a signal and I am sure that signal runs
note2= I do not want to destroy window for that
note3= I use gtk+ and pygtk
note4= I am sure I attach that widget to a correct position ( it is free)
Did you call gtk_widget_show() on label first?