Dynamically adding instances of a view to a TransparentContainer - abap

I have a scenario where I'd like to N instances of a view to the TransparentContainer on a view with each receiving different parameters. To accomplish this I wrote some logic to dynamically create a cl_wd_view_container_uielement, add it to the cl_wd_uielement_container (the TransparentContainer on the main view) and then fire a plug using dynamic navigation to send my parameters. The code can be found below.
This all works with one problem: the created instances are not unique so I basically add N copies of the same view. N plugs are fired and handled but the last one sets the parameters for all views as there's just one instance. The view's WDDOMODIFYVIEW is also only fired once.
The code below was repurposed and cleaned up from a working version so I know it's possible. The big difference is that I'm adding a view from the same WDC in my scenario. In the original application the dynamically added view has its own Web Dynpro component and the caller also provides a dynamically created component usage.
Is there some way of creating multiple instances that I'm missing? Should I provide a component usage after all in this case? I've been tinkering with this for a few hours now but am not making any progress so I'd welcome any input to get me on the right track.
Code from the main view:
DATA:
lo_container TYPE REF TO cl_wd_uielement_container,
lo_subview TYPE REF TO cl_wd_view_container_uielement,
lo_flow_data TYPE REF TO cl_wd_flow_data,
lo_view_controller TYPE REF TO if_wd_view_controller,
lo_component_usage TYPE REF TO if_wd_component_usage,
lo_wdr_view TYPE REF TO cl_wdr_view,
lo_component_api TYPE REF TO if_wd_component,
lt_posts TYPE ztt_fi_vernot_posts,
ls_post LIKE LINE OF lt_posts,
lt_parameters TYPE wdr_event_parameter_list,
ls_parameter TYPE wdr_event_parameter,
lv_view_id TYPE string,
lv_source_plug_name TYPE string,
lv_target_embed_pos TYPE string,
lv_param_value TYPE REF TO DATA.
FIELD-SYMBOLS:
<lv_param_value> TYPE bu_partner
.
lt_posts = wd_this->mo_model->get_posts( iv_open = abap_true ).
" Retrieve and refresh the view container.
lo_wdr_view ?= wd_this->wd_get_api( ).
lo_container ?= lo_wdr_view->root_element.
lo_container ?= lo_wdr_view->get_element( 'TC_POSTS' ).
lo_container->remove_all_children( ).
LOOP AT lt_posts INTO ls_post.
" View and plug IDs should be unique.
CONCATENATE 'POSTS_' ls_post-index INTO lv_view_id.
CONCATENATE 'OUTPLUG_' ls_post-index INTO lv_source_plug_name.
" Create a new view.
lo_subview = cl_wd_view_container_uielement=>new_view_container_uielement( id = lv_view_id ).
lo_flow_data = cl_wd_flow_data=>new_flow_data( element = lo_subview ).
lo_subview->set_layout_data( lo_flow_data ).
lo_subview->set_layout_data( cl_wd_flow_data=>new_flow_data( element = lo_subview ) ).
lo_container->add_child( lo_subview ).
lo_view_controller = wd_this->wd_get_api( ).
CONCATENATE 'V_MAIN/' lv_view_id INTO lv_target_embed_pos.
* This was present in the source, returning a component usage via create_comp_usage_of_same_type()
* lo_component_usage = wd_comp_controller->get_component( iv_compcnt = ls_post-index ).
lo_view_controller->prepare_dynamic_navigation(
source_window_name = 'W_MAIN'
" Found in the window structure for this View
source_vusage_name = 'V_MAIN_USAGE_0'
source_plug_name = lv_source_plug_name
" target_component_name = '[WDC name]' " Optional?
" target_component_usage = lo_component_usage->name " Optional?
target_view_name = 'V_POSTS'
target_plug_name = 'SET_PARAMS'
target_embedding_position = lv_target_embed_pos ).
" Fill the paramaters. Note that the values should be passed as pointers.
REFRESH lt_parameters.
CLEAR ls_parameter.
ls_parameter-name = zcl_fi_vernot=>gcs_plugs-params-bp.
CREATE DATA lv_param_value LIKE ls_post-bp.
ASSIGN lv_param_value->* TO <lv_param_value>.
<lv_param_value> = ls_post-bp.
ls_parameter-value = lv_param_value.
INSERT ls_parameter INTO TABLE lt_parameters.
" Do the same for the contract.
CLEAR ls_parameter.
ls_parameter-name = zcl_fi_vernot=>gcs_plugs-params-contract.
CREATE DATA lv_param_value LIKE ls_post-contract.
ASSIGN lv_param_value->* TO <lv_param_value>.
<lv_param_value> = ls_post-contract.
ls_parameter-value = lv_param_value.
INSERT ls_parameter INTO TABLE lt_parameters.
" Finally, fire the plug.
wd_this->wd_get_api( )->fire_plug( plug_name = lv_source_plug_name parameters = lt_parameters ).
ENDLOOP.

This problem is not limited to dynamic generation of views but also occurs when you want to use a particular view more than once in a window of the same component. Only one instance is created so reuse is very limited.
The only solution to this would be to separate the the View off to its own Web Dynpro component or to create multiple component usages of the active WDC and using those in dynamic navigation.

Related

How to get all attributes of a view in crm?

In Transaction BSP_WD_CMPWB I found a view from the WebUI Client.
I want to write a method that gets all the values of the attributes of the view structure.
How do I do this?
I think I need to find out somehow which BOL-Object this view structure belongs to...but I don't really know.
I started out like this...but no idea if I'm on the right track there :D
DATA:
ls_view TYPE "How do I find out the structure type name of my view, does it even exist?
lv_query_name TYPE CRM_OBJEXT_NAME VALUE. "How do I find out the query name I need to pass to get my view structure?
lr_query = cl_crm_iu_order_agent=>create_order_item_query_int( lv_query_name ).
ls_parameter-name = 'BUPA_NUMBER'. "This is an example filter for my specific case
ls_parameter-value = iv_partner.
APPEND ls_parameter TO lt_paramater.
lr_query->set_query_parameters( it_parameters = lt_paramater ).
lr_result = lr_query->get_query_result( ).
CHECK lr_result IS BOUND.
lr_bol = lr_result->get_first( ).
lr_bol->get_properties( IMPORTING es_attributes = ls_view ).

Create subobject programmatically, not in SLG0

When creating a new log object I want the subobject to be created on the fly if it doesn't exist yet.
This is what I have right now:
ls_log-object = mc_log_object.
ls_log-subobject = mv_log_subobject.
CALL FUNCTION 'BAL_LOG_CREATE'
EXPORTING
i_s_log = ls_log
IMPORTING
e_log_handle = mv_log_handle.
In order to avoid an error I check the object and subobject like this before:
CALL FUNCTION 'BAL_OBJECT_SUBOBJECT_CHECK'
EXPORTING
i_object = mc_log_object
i_subobject = mv_log_subobject
EXCEPTIONS
object_not_found = 1
subobject_not_found = 2
subobject_necessary = 3
OTHERS = 4.
CASE sy-subrc.
WHEN 2.
mv_log_subobject = ''.
ENDCASE.
But I don't want to do it like this, I want to create a new subobject if it doesn't exist yet!
Is there some secret function call that can do this? :D
There is no secret function call or something similar. In fact SLG0 is nothing else than view cluster maintenance call (SM34). But I'm also wondering why you need this? If you need some more or dynamic differentiation of your logs you can you use field "extnumber" which you can set in your structure ls_log.
You can select in SLG1 with this field and also via log api.

Set property to empty - SAP CRM WebUI

I am new to SAP, and am encountering an issue I am not sure how to resolve.
I am setting a property to '' (empty), but it is not being displayed as such.
There is existing logic that sets specific fields to 'Display Only' when a checkbox is checked. I am working to extend this to clear any data that is within those fields. Due to how the original logic was implemented, this change is being handled in the "Get_..." method (may be moved to an event handler once I get it working).
Currently, the logic sets the property to be empty (I have confirmed this with debug); however, the webpage keeps the original value. A shortened outline of the code is below (all try catches, etc. removed to keep it short and simple):
DATA: current TYPE REF TO if_bol_bo_property_access.
DATA: dref TYPE REF TO data.
current = collection_wrapper->get_current( ).
dref = current->get_property( 'FIRSTNAME' ).
* If condition
DATA: copy TYPE REF TO data.
FIELD-SYMBOLS:
<nval> TYPE ANY,
<oval> TYPE ANY.
ASSIGN dref->* TO <oval>.
CREATE DATA copy LIKE <oval>.
CLEAR value.
TRY.
CALL METHOD if_bsp_model_util~convert_from_string
EXPORTING
data_ref = copy
value = value
attribute_path = attribute_path.
CATCH cx_sy_conversion_error.
RAISE EXCEPTION TYPE cx_bsp_conv_failed
EXPORTING
name = 'FIRSTNAME'.
ENDTRY.
current->set_property_as_string(
iv_attr_name = 'FIRSTNAME'
iv_value = value ).
value = current->get_property_text( 'FIRSTNAME' ). "Check empty ''
Most of this was pulled from the 'Set_...' method. Any help would be appreciated.
This issue is due to the CRM browser autosaving before the case is complete. This causes the values to be rendered as though they are cached.
Note 2104051 resolves this.

Alv OO program error Message no. 0K534

Everytime i hit enter or any command button the program prompt an error message.
base on this thread http://scn.sap.com/thread/65856 i should declare my internal table
globally on top include.
Even though i already added all variable globally still the error is the same.
Top Include.
data: gr_data type ref to data.
data: la_data type ref to data.
field-symbols: <gt_data> type standard table.
Classs Declaration
me->get_data( CHANGING c_data = <f_tab> ). " Fetch Dynamic Data
METHOD get_data.
GET REFERENCE OF c_data INTO la_data.
move la_data TO gr_data.
assign gr_data->* to <gt_data>.
me->display( ).
assign gr_data->* to <gt_data>.
IF gc_custom_container is initial.
CREATE OBJECT gc_custom_container
EXPORTING
container_name = gv_mycontainer.
ENDIF.
if table is not bound.
try.
"// Create ALV Instance
cl_salv_table=>factory(
exporting
r_container = gc_custom_container
container_name = 'TC_MIXING'
importing
r_salv_table = table
changing
t_table = <gt_data>
).
catch cx_salv_msg. "#EC NO_HANDLER
endtry.
"// Setup ALV Attributes
functions = table->get_functions( ).
functions->set_all( abap_true ).
columns = table->get_columns( ).
columns->set_optimize( abap_true ).
try.
column = columns->get_column( 'MANDT' ).
column->set_technical( if_salv_c_bool_sap=>true ).
catch cx_salv_not_found.
endtry.
"// Dispalay ALV Model
table->display( ).
else.
table->refresh( ).
endif.
ENDMETHOD.
and another question:
how to create structure dynamically base on field-symbol. is this possible?
ls_testvar like line of <f_tab>.
thanks and regards,
Mapet
Question two is possible, with some usage of runtime type services.
Take a look at runtime type services.
se24
CL_ABAP_CLASSDESCR Run Time Type Services
CL_ABAP_DATADESCR Run Time Type Services
CL_ABAP_ELEMDESCR Run Time Type Services
CL_ABAP_INTFDESCR Run Time Type Services
CL_ABAP_OBJECTDESCR Run Time Type Services
CL_ABAP_REFDESCR Run Time Type Services
CL_ABAP_STRUCTDESCR Run Time Type Services
CL_ABAP_TABLEDESCR Run Time Type Services
CL_ABAP_TYPEDESCR Run Time Type Services
You can get the type of the fieldsymbol and create a structure based on it, perhaps You have to iterate through fieldsymbol, if it is composed type and add each component.
I agree, you should not pass a field symbol to the changing parameter for the table data! Use a global or static table. You should also use a typed table instead of data and create your field catalog in design time. This improves the performance a lot.
Cheers
Your table variable holding the ALV must be declared globally as well.
cl_salv_table=>factory(
exporting
r_container = gc_custom_container
container_name = 'TC_MIXING'
importing
r_salv_table = table
changing
t_table = <gt_data>
).
You should separate data retrieving from your displaying code like this:
START-OF-SELECTION.
gr_class->get_data( ).
CALL SCREEN 2000.
PBO:
gr_class->display.
Your display method:
METHOD display IMPLEMENTATION.
IF me->gr_container IS NOT BOUND.
gr_table->display( ).
ELSE.
gr_table->refresh( ).
ENDIF.

How do I get my data to show up in my ALV?

I'm thinking that I'm probably missing an export parameter (from my Function Call POV).
In the REUSE_ALV_GRID_DISPLAY function call, the parameters I pass around are:
Exporting:
i_callback_program,
i_callback_pf_status_set,
i_callback_user_command,
is_layout,
it_fieldcat,
i_save
Tables:
t_outtab
And the exceptions plus handling.
I've checked that the internal table that I pass has data and it does.
I think the information I put up will suffice but if you really need to see the code, I'll do so.
I'm a noob and any help would be appreciated.
Thanx.
There are several ways to use ALV, so we may indeed need more info on your code to help.
First Method is to use the function module REUSE_ALV_GRID_DISPLAY. This will directly display the table content in the output dynpro. If all you need is a display, then go for it, as this is the simpliest : If the table structure is in the dictionnary, this call can be as simple as the following (this will display all members of the struct as column)
myreport = sy-repid.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
EXPORTING
i_callback_program = myreport
it_excluding = exclude_tab
TABLES
t_outtab = display_data
EXCEPTIONS
program_error = 1
OTHERS = 2.
If the structure is declared in the program, then you have to create a field catalog.
the following code can serve as basis :
FORM fill_fieldcat CHANGING p_fieldcat TYPE slis_t_fieldcat_alv.
* Data definition
DATA ls_fieldcat TYPE slis_fieldcat_alv.
* Macro definition
DEFINE append_fieldcat.
clear ls_fieldcat.
ls_fieldcat-fieldname = &1. * name of the field in struct
ls_fieldcat-tabname = &2. * name of the table
ls_fieldcat-row_pos = &3. * column
ls_fieldcat-ref_fieldname = &4. * field in ref table
ls_fieldcat-ref_tabname = &5. * ref table
ls_fieldcat-outputlen = &6. * size of output
ls_fieldcat-seltext_m = &7. * text (space if using the element typetext)
ls_fieldcat-ddictxt = 'M'.
ls_fieldcat-key = &8. * is this a key field in table
ls_fieldcat-emphasize = &9. * emphisze column display
append ls_fieldcat to p_fieldcat.
END-OF-DEFINITION.
* Init.
REFRESH p_fieldcat.
* Append fielcatalog for ALV
append_fieldcat:
'FORMATIONCODE' 'DISPLAY_TAB' 1 'SHORT' 'HRP1000' 12 'Code Stage' space space,
'FORMATIONTEXT' 'DISPLAY_TAB' 1 'STEXT' 'HRP1000' 20 'Libelle Stage' space space,
'SESSIONID' 'DISPLAY_TAB' 1 'OBJID' 'HRP1000' space 'Session' space space,
'BEGDA' 'DISPLAY_TAB' 1 'BEGDA' 'HRP1000' space 'Debut' space space,
'ENDDA' 'DISPLAY_TAB' 1 'BEGDA' 'HRP1000' space 'Fin' space space,
ENDFORM. "fill_fieldCat
you then call the form to create the field catalog, and use it in the it_fieldcat parameter of the function call.
Second method is to use ABAP-Object. Use check se83 for exemples of this use. the basis is as follows :
In your Dynpro you declare a custom container with a given name ("ALV_CONT"). Then in then PBO of the dynpro you initialize the container and put an ALV objct inside :
* global variables :
DATA : delegationlist_table TYPE REF TO cl_gui_alv_grid,
delegationlist_container TYPE REF TO cl_gui_custom_container.
data : gs_layout TYPE lvc_s_layo.
in PBO
IF delegationlist_container IS INITIAL.
* create a custom container control for our ALV Control
CREATE OBJECT delegationlist_container
EXPORTING
container_name = 'ALV_CONT'
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
create_error = 3
lifetime_error = 4
lifetime_dynpro_dynpro_link = 5.
* create an instance of alv control
CREATE OBJECT delegationlist_table
EXPORTING
i_parent = delegationlist_container.
* Set a titlebar for the grid control
gs_layout-grid_title = 'Délégations'.
gs_layout-sel_mode = 'A'.
gs_layout-cwidth_opt ='X'.
* set table as data source
* the struct name *must* be uppercase
* the table must have this struc
CALL METHOD delegationlist_table->set_table_for_first_display
EXPORTING
i_structure_name = 'ZPRT_DELEGATIONLIST'
is_layout = gs_layout
CHANGING
it_outtab = delegationlist.
ENDIF.
Hopes this help,
Regards
Guillaume PATRY
EDIT: Oh, and another thing - if you're really in POV (process on Value-Request = F4), be aware that there are limitations to what you can do. Try your code in a simple report right after START-OF-SELECTION, and if that works, try the same code in a POV module.
===
If you don't pass a structure name, you have to ensure that you pass a complete (!) field catalog, otherwise the ALV grid might start to work erratically or not at all. Use the function modules LVC_FIELDCATALOG_MERGE and LVC_FIELDCAT_COMPLETE (in this order) to get a LVC field catalog that can be used with the classes or REUSE_ALV_GRID_DISPLAY_LVC.
A couple people here suggested using the REUSE_ALV_GRID_DISPLAY. I'm sure this is a common way to get things done (I used to use it myself), but I've taken a sap delta course recently and they strongly suggested to not use it anymore (you can look it up, REUSE_ALV_GRID_DISPLAY is not officialy supported by SAP anymore).
Instead, use CL_SALV_TABLE, documentation here: http://help.sap.com/erp2005_ehp_04/helpdata/EN/d7/b22041aa7df323e10000000a155106/frameset.htm
It's actually rather convenient to use too.
Thanks for the effort but as it turned out, the mistake I did was that I didn't capitalize field names in building the Field Catalog. Such a newbie mistake. I guess I won't be doing that mistake again any time soon.
-migs
Pass the output internal table to the FM Parameter "t_outtab".
It will print your data output.