We have a scenario wherein the application shows a basket of services/materials that the user has added for saving. The basket by default shows only 5 rows and it has the pagination buttons at the bottom. If the user adds more than 5 items and he wants to do a print of the page then all the items in the basket will not be shown. So we decided to create another Web Dynpro component that will just show the contents of a table so that the user can print all the data in the basket if he wishes to. This component will have to be generic one as we want all basked based applications to use this functionality. When transferring the internal table from one component to the other we will also send the information on the UI of the columns as the columns might have different caption than what is given by the data dictionary. There are also some columns which will have a dropdown by key text editor for that we need to send the value set for the element in the context.
Here is how the basket will look like with a print button on top of the table, the table has 9 rows but is showing only 5 rows at a time:
The print basket view will show all the rows of the basket:
Let’s see how we achieved this. To transfer data across the two components we created a class that contains the table data. We have called this class ZCL_BASKET.
The attributes in the class are as follows:
T_COLUMNS | Instance Attribute | Private | Type | CL_WD_TABLE_COLUMN=>TT_TABLE_COLUMN | Columns |
T_VALUE_SET | Instance Attribute | Private | Type | ZRC_BASKET_VALUE_SET_T | Value set for drop down |
O_UIBASKET | Instance Attribute | Private | Type Ref To | CL_WD_TABLE | UI Basket |
O_BASKET_TYPE | Instance Attribute | Private | Type Ref To | CL_ABAP_STRUCTDESCR | Basket type |
DESCRIPTION | Instance Attribute | Private | Type | STRING | Description |
BASKET | Instance Attribute | Private | Type Ref To | DATA | Basket |
The methods defined are:
GET_VALUE_SET | Instance Method | Public | Returns the value set |
REPLACE_DROPDOWN_TO_TEXT | Instance Method | Private | |
GET_COLUMNS | Instance Method | Public | Get columns |
GET_UIBASKET | Instance Method | Public | Get UI Basket |
CONSTRUCTOR | Instance Method | Public | CONSTRUCTOR |
GET_BASKET | Instance Method | Public | |
GET_BASKET_TYPE | Instance Method | Public | |
GET_DESCRIPTION | Instance Method | Public |
The interesting method for us is the constructor that:
- gets the data in it’s private attributes.
- gets the RTTI value of the table.
- Save the column UI for the basket to be used in the print view
METHOD constructor.DATA l_o_tabledescr TYPE REF TO cl_abap_tabledescr.FIELD-SYMBOLS <l_basket> TYPE table.o_uibasket = i_o_uibasket.t_columns[] = i_t_columns[].t_value_set[] = i_t_value_set[].l_o_tabledescr ?= cl_abap_tabledescr=>describe_by_data( i_t_basket ).o_basket_type ?= l_o_tabledescr->get_table_line_type( ).description = i_description.CREATE DATA basket TYPE HANDLE l_o_tabledescr.ASSIGN basket->* TO <l_basket>.<l_basket> = i_t_basket[].ENDMETHOD.
We have a Web Dynpro component ZWDRC_PRINT_BASKET which has a view V_PRINT_BASKET embedded into the window ZWDRC_PRINT_BASKET. The print basket component is of the following structure:
The inbound plug FROM_ANOTHER_VIEW in the window ZWDRC_PRINT_BASKET is the one to be used as standard and not a startup type because startup plug does not take parameters of type reference. This is the inbound plug that will be used by other calling components. Code for the the plug is:
METHOD handlefrom_another_view .wd_comp_controller->o_basket = i_o_basket.ENDMETHOD.
The parameters defined are:
Details of the view V_PRINT_BASKET is:
The layout is empty as we plan to create elements dynamically in the WDDOMODIFYVIEW method.
From the method WDDOMODIFYVIEW call to is made to the PRINT_BASKET method which will add the dynamic table with data from the class ZCL_BASKET. I have referenced the code from this blog posting for creating dynamic table.
METHOD print_basket .DATA: group TYPE REF TO cl_wd_group , "for dynamic group ui element.capt_gr TYPE REF TO cl_wd_caption , "caption for group_2new_tab TYPE REF TO cl_wd_table ,rootelem TYPE REF TO if_wd_view_element , "to get root elementrootnode TYPE REF TO cl_wd_transparent_container , "to store root “nodedyn_node TYPE REF TO if_wd_context_node ,tabname_node TYPE REF TO if_wd_context_node ,rootnode_info TYPE REF TO if_wd_context_node_info ,child_node_info TYPE REF TO if_wd_context_node_info ,stru_tab TYPE REF TO data,tablename TYPE string.DATA l_description TYPE string.DATA l_o_basket_type TYPE REF TO cl_abap_structdescr.DATA l_o_layout TYPE REF TO cl_wd_layout_data.DATA lt_value_set TYPE zrc_basket_value_set_t.FIELD-SYMBOLS <l_value_set> TYPE zrc_basket_value_set.FIELD-SYMBOLS: <tab> TYPE table.DATA l_t_columns TYPE cl_wd_table_column=>tt_table_column.DATA l_path TYPE string.DATA cell_edi TYPE REF TO cl_wd_uielement.FIELD-SYMBOLS <l_column> TYPE REF TO cl_wd_table_column.* Get the columns that need to be shownl_t_columns = wd_comp_controller->o_basket->get_columns( ).* Get the context path referenced in the columnsLOOP AT l_t_columns ASSIGNING <l_column>.cell_edi ?= <l_column>->get_table_cell_editor( ).l_path = cell_edi->bound__primary_property( ).EXIT.ENDLOOP.SPLIT l_path AT '.' INTO tablename l_path.IF i_first_time = abap_true.* Get description of the basketl_description = wd_comp_controller->o_basket->get_description( ).* Get the basket typel_o_basket_type = wd_comp_controller->o_basket->get_basket_type( ).***** to get root node info in the context.rootnode_info = wd_context->get_node_info( ).* Create child node referencing the table structureCALL METHOD rootnode_info->add_new_child_nodeEXPORTING* SUPPLY_METHOD =* SUPPLY_OBJECT =* DISPOSE_METHODS =* DISPOSE_OBJECT =* STATIC_ELEMENT_TYPE =name = tablename* IS_MANDATORY = ABAP_FALSE* IS_MANDATORY_SELECTION = ABAP_FALSE* IS_MULTIPLE = ABAP_TRUE* IS_MULTIPLE_SELECTION = ABAP_TRUE* IS_SINGLETON = ABAP_FALSE* IS_INITIALIZE_LEAD_SELECTION = ABAP_TRUEstatic_element_rtti = l_o_basket_type* IS_STATIC = ABAP_TRUE* ATTRIBUTES =RECEIVINGchild_node_info = child_node_info.* Add value set if there are anylt_value_set = wd_comp_controller->o_basket->get_value_set( ).IF lt_value_set IS NOT INITIAL.LOOP AT lt_value_set ASSIGNING <l_value_set>.child_node_info->set_attribute_value_set( name = <l_value_set>-attributevalue_set = <l_value_set>-value_set ).ENDLOOP.ENDIF.**** to get the ref to rootuielementcontainer in the viewCALL METHOD i_view->get_root_elementRECEIVINGroot_view_element = rootelem.rootnode ?= rootelem .**** if group already exists in the, to remove it.**** this case only occurs, IF you ARE running APPLICATION just by refreshing.**** precautionary check for existence of group_2rootnode->remove_child( id = 'GROUP' ).**** to create a new groupgroup = cl_wd_group=>new_group( view = i_viewid = `GROUP`design = `01`enabled = abap_truehas_content_padding = abap_truescrolling_mode = `02`visible = `02` ).**** to add a caption to the groupcapt_gr = cl_wd_caption=>new_caption( view = i_viewid = `CAPT_GR`enabled = abap_trueimage_first = abap_truetext = l_descriptiontext_direction = `02`visible = `02` ).**** To set the Caption to the Groupgroup->set_header( capt_gr ).**** To set the layout for the group_2cl_wd_grid_layout=>new_grid_layout( container = groupcell_padding = `0`cell_spacing = `0`col_count = `2`stretched_horizontally = abap_truestretched_vertically = abap_true ).cl_wd_flow_data=>new_flow_data( element = groupcell_design = `04`v_gutter = `00` ).rootnode->add_child( group ) .dyn_node = wd_context->get_child_node( name = tablename ).*** create a table ui element from context and assigning it to group_2.new_tab = cl_wd_dynamic_tool=>create_table_from_node( ui_parent = grouptable_id = 'BASKET'node = dyn_node ).new_tab->remove_all_columns( ). " Remove all columns
new_tab->set_design( 01 ). " Standard
new_tab->set_read_only( abap_true ).* Now set only the columns that need to be displayedLOOP AT l_t_columns ASSIGNING <l_column>.<l_column>->register_to_view( i_view ). " Imp register the columns to this view
new_tab->add_column( <l_column> ).ENDLOOP.CALL METHOD new_tab->set_footer_visibleEXPORTINGvalue = abap_false.CALL METHOD new_tab->set_selection_modeEXPORTINGvalue = 06.ENDIF.IF dyn_node IS INITIAL.dyn_node = wd_context->get_child_node( name = tablename ).ENDIF.* Get basket valuesstru_tab = wd_comp_controller->o_basket->get_basket( ).ASSIGN stru_tab->* TO <tab>.dyn_node->bind_table( <tab> ).ENDMETHOD.
The highlights in the method are:
- Getting the name for the new child node from the UI column information, the name has to be same as the basket context so that the new columns will refer this new context automatically.
- Adding a new child node using the RTTI information of the basket table
- Adding a new UI table from the above node
- Adding columns to this table taken from the UI of the original basket
- Binding of the data to the node
Let’s now see how the call has to be made from the a basket based application. First we have to include the component in the calling Web Dynpro used component.
In the calling Web Dynpro component we will make another view called V_PRINT_BASKET.
This will have a ViewContainer for embedding the print view. It will also have an outbound plug which will take the navigation back to the calling basket. The window of this application will have the following layout:
In the basket view we have to create one inbound plug FROM_V_PRINT_BASKET and one outbound plug TO_V_PRINT_BASKET with a parameter basket of type ZCL_BASKET.
As seen above we have a print button on the basket table. Let’s see the code that will be required to handle the action on the button.
METHOD onactionprint_basket .DATA l_o_basket TYPE REF TO zcl_rc_basket.DATA l_o_uibasket TYPE REF TO cl_wd_table.DATA lt_columns TYPE cl_wd_table_column=>tt_table_column.DATA lt_value_set TYPE wdy_key_value_list.DATA ls_basket_value_set TYPE zrc_basket_value_set.DATA lt_basket_value_set TYPE zrc_basket_value_set_t.DATA:node_materialsinbasket TYPE REF TO if_wd_context_node,table_materialsinbasket TYPE TABLE OF if_v_basket=>element_n_basket.* navigate from <CONTEXT> to <materialsINBASKET> via lead selectionnode_materialsinbasket = wd_context->get_child_node( name = if_v_basket=>wdctx_n_basket ).* @TODO handle not set lead selectionIF ( node_materialsinbasket IS INITIAL ).RETURN.ENDIF.* get element via lead selectionnode_materialsinbasket->get_static_attributes_table( IMPORTING table = table_materialsinbasket ).* get the table uielementl_o_uibasket ?= wd_this->o_view->get_element( 'T_BASKET' ).lt_columns = l_o_uibasket->get_columns( ).*********************************************************************** Add value set for dropdown listls_basket_value_set-value_set = wd_assist->get_reg_st_values( ).ls_basket_value_set-attribute = 'COL1'.APPEND ls_basket_value_set TO lt_basket_value_set.ls_basket_value_set-value_set = wd_assist->get_clm_ty_values( ).ls_basket_value_set-attribute = 'COL2'.APPEND ls_basket_value_set TO lt_basket_value_set.**********************************************************************CREATE OBJECT l_o_basket EXPORTING i_t_basket = table_materialsinbasketi_description = 'Basket'i_o_uibasket = l_o_uibasketi_t_columns = lt_columnsi_t_value_set = lt_basket_value_set.wd_this->fire_to_v_print_basket_plg(i_o_basket = l_o_basket " Ref to zcl_Rc_Basket
).ENDMETHOD.
In the above code:
- Get the UI columns
- For the columns where drop down by key is used get the value set
- Create object basket referring to ZCL_BASKET
- Fire outbound plug V_PRINT_BASKET
So these were the necessary steps to do the print basket view from any given table based application.