Drag and Drop in Tree Type BSP View
Applies to:
SAP CRM 7.0, EHP1 and EHP2
Summary
This particular document illustrates step by step procedure to first create a tree type view in BSP workbench. Then include the Drag & Drop functionality in the same. The drag and drop functionality makes the maintenance easy for the customer wherein user just needs to drag the data from one node of the tree to another node of the tree without any hassles. The inspiration for this document is the complex object which I had worked on wherein I had to introduce the same although the scenario was very complex as the tree was recursive and have n number of children with their children having n number of children and so on(the whole logic of getting the data for the tree was encompassed in LORDS Class). I wasn’t able to reproduce the same scenario in this document but tried to summarize the steps which I had used taking into consideration that in this document I am just having the tree with 1 level of child.
Important point to note: This particular illustration will be valid only when we are trying to drag & drop child node from One parent node to another parent Node. Dragging and dropping the parent node is not possible in this as this is simple step by step illustration.
Author(s): Rajwin Singh Sood
Company: Atos
Created on: 13th Mar 2014
Author Bio
Rajwin Singh Sood is currently working as Team lead/Solution Architect at Atos. He has got experience of about 9 years in SAP ABAP and SAP CRM web UI. He is also a SAP CRM EHP2 Certified associate consultant. Prior to working with Atos he had worked with SAP India(SAP Global Delivery), Capgemini , Accenture and Infosys. He worked in SAP CRM Web UI areas like BSP enhancements, transaction launchers, BOL Programming, BRFPlus .
Table definition for the tree type view
We’ll be using a very simple transparent table which will be having the field to capture the parent. Please refer to the below screenshot:-
Where the parent ID will be pointing to the parent of that tree. After activating the table please enter the data in the table:-
View Creation in BSP
This is the first step wherein we’ll be creating a simple view in BSP workbench before converting the same in to Tree type View. Please not that you could create the ZBOL for the same but over here I’ll be incorporating the logic of fetching the data in DO_INIT method of BSP Workbench. For implementing the same into ZBOL you can refer to my previous Blog the link is given below:-
http://scn.sap.com/docs/DOC-52830
Now go to BSP workbench transaction BSP_WD_CMPWB and create a new BSP Component:-
After this create a View with the Value node and in the value node add the structure as ZTREE_PRODUCT so that all the attributes will appear as it is and in the final step of the wizard make the view as table type view and click on the check box of configuration where in finally you’ll get the view as:-
After this as mentioned that we’ll incorporating the logic of fetching the data in DO_INIT. We’ll be having the public instance internal table variable which will of type table ZTREE_PRODUCT created in the above step. Please refer to the screenshots given below:-
And the code snippet is :-
Now this global variable will be used wherever we need to retrieve or change data as this has been loaded once the BSP Component is loaded.
Steps for converting that View to tree type View
Now as our view is ready we now need to convert the same into tree type view. This particular section you can refer to SCN as there are many blogs written on the same. But I’ll be still covering it up here in order to maintain the consistency of the document. The steps are enumerated below:-
Step1: We need to change the super class of the context node class which was automatically created in the view creation step to CL_BSP_WD_CONTEXT_NODE_TREE from CL_BSP_WD_CONTEXT_NODE.
Once you do that now once you expand the context node you’ll see it will look like the one given below with the new Method REFRESH in addition to IF_BSP_MODEL~INIT and GET_TABLE_LINE_SAMPLE which were again automatically created while creating the simple view.
Step2: The refresh method which appeared in the above screenshot needs to be redefined so that it will instantiate the proxy class to get the children of the root node. The important part in converting any view to tree type view is first refresh method and then creation of Proxy class as in refresh method we’ll be first instantiating the proxy class and then the root element(parent) is also added to the view. Please refer to the screenshot as well as the code snippet below:-
METHOD refresh.
*CALL METHOD SUPER->REFRESH
* .
DATA : lr_iterator TYPE REF TO if_bol_bo_col_iterator,
lr_entity TYPE REF TO if_bol_bo_property_access,”cl_crm_bol_entity,
lr_root TYPE REF TO if_bsp_wd_tree_node.
TRY.
lr_iterator = me->collection_wrapper->get_iterator( ).
lr_entity ?= lr_iterator->get_first( ).
WHILE lr_entity IS BOUND.
lr_root = me->node_factory->get_proxy(
iv_bo = lr_entity
iv_proxy_type = ‘ZCL_PRODUCT_TREE’ ).
lr_root->node_key = add_root_node( lr_root ).
* exit.
lr_entity ?= lr_iterator->get_next( ).
ENDWHILE.
CATCH cx_sy_move_cast_error cx_sy_ref_is_initial.
ENDTRY.
- ENDMETHOD.
Step3: Now we need to create the Proxy class which we had instantiated in the refresh method as defined in step2 above. Please note it’s the proxy class method GET_CHILDREN which actually picks up the children of the parent node in the view and will be invoked once we try to expand the parent node in the browser. Please refer to the screenshot for the class creation as well as code snippet for the GET_CHILDREN as shown below:-
METHOD if_bsp_wd_tree_node~get_children.
*CALL METHOD SUPER->IF_BSP_WD_TREE_NODE~GET_CHILDREN
** EXPORTING
** is_sort_wish =
* RECEIVING
* RT_CHILDREN =
* .
TYPES: BEGIN OF line,
product_id TYPE zprod_id,
prod_company TYPE zprod_company,
prod_type TYPE zprod_root_type,
parent_id TYPE zprod_id,
END OF line.
DATA: lr_child TYPE REF TO if_bsp_wd_tree_node,
lv_size_s TYPE i,
lv_size_d TYPE i,
lr_current TYPE REF TO if_bol_bo_property_access,
lr_iterator TYPE REF TO if_bol_bo_col_iterator,
lv_parent TYPE zprod_id,
ls_prod_tree_par TYPE ztree_product,
ls_product_tree TYPE ztree_product.
DATA : lr_valuenode TYPE REF TO cl_bsp_wd_value_node,
lr_col TYPE REF TO if_bol_bo_col,
lr_tabline TYPE REF TO line,
ls_tabline TYPE line.
DATA: lv_entity TYPE REF TO if_bol_bo_property_access.
CREATE OBJECT lr_col TYPE cl_crm_bol_bo_col.
lr_current ?= me->bo.
lr_current->get_property_as_value( EXPORTING iv_attr_name = ‘PRODUCT_ID’ IMPORTING ev_result = lv_parent ).
CALL METHOD lr_current->get_properties
IMPORTING
es_attributes = ls_prod_tree_par.
.
CHECK ls_prod_tree_par-parent_id IS INITIAL.
APPEND ls_prod_tree_par TO lt_prod_tree.
IF lv_parent IS NOT INITIAL.
LOOP AT zl_zbsp_tre_product_impl=>gt_tree_product INTO ls_product_tree WHERE parent_id EQ lv_parent.
CREATE DATA lr_tabline.
CREATE OBJECT lr_valuenode
EXPORTING
iv_data_ref = lr_tabline.
CLEAR ls_tabline.
MOVE-CORRESPONDING ls_product_tree TO ls_tabline.
lr_valuenode->set_properties( ls_tabline ).
lr_col->add( lr_valuenode ).
ENDLOOP.
ENDIF.
lv_entity ?= lr_col->get_first( ).
WHILE lv_entity IS BOUND.
lr_child = me->node_factory->get_proxy(
iv_bo = lv_entity
iv_parent_proxy = me
iv_proxy_type = ‘ZCL_PRODUCT_TREE’ ).
lr_child->is_leaf = abap_false.
lr_child->expand_node( ).
APPEND lr_child TO rt_children.
lv_entity ?= lr_col->get_next( ).
ENDWHILE.
- ENDMETHOD.
After this you can see once expand the context node in BSP workbench it will look like the one in the below screenshot:-
Step4: the step 4 is the place where we’ll define the configuration in the configuration tab and change the iterator in the HTM code (View Layout) in order to display the view as tree type view in Browser.
First the HTM code screenshot and snippet
The HTM code :-
<%@page language=”abap” %>
<%@extension name=”thtmlb” prefix=”thtmlb” %>
<%@extension name=”chtmlb” prefix=”chtmlb” %>
<%@extension name=”bsp” prefix=”bsp” %>
<%–<thtmlb:toolbar buttons = “<%= controller->IF_BSP_WD_DYN_BTN_CONTROL~GET_LOCAL_TOOLBAR_BUTTONS( ) %>”
foreignUse = “TRUE”
id = “tabtoolbar”
maxButtonNumber = “<%= controller->IF_BSP_WD_DYN_BTN_CONTROL~GET_NO_OF_VISIBLE_TOOLBAR_BTNS( ) %>” />–%>
<%
* Conversion Cnode SelectionMode to Tag
data: lv_cellerator_selectionmode type string,
lv_cellerator_editmode type string,
lv_cellerator_selectioncolumn type string.
cl_thtmlb_util=>translate_selection_mode(
exporting
iv_selection_mode = Product->SELECTION_MODE
iv_all_rows_editable = space
importing
ev_selection_mode = lv_cellerator_selectionmode
ev_edit_mode = lv_cellerator_editmode
ev_selection_column = lv_cellerator_selectioncolumn ).
%>
<%–<chtmlb:configCellerator downloadToExcel = “TRUE”
editMode = “<%= lv_cellerator_editmode %>”
id = “ConfCellTable”
onRowSelection = “select”
personalizable = “TRUE”
selectedRowIndex = “<%= Product->SELECTED_INDEX %>”
selectedRowIndexTable = “<%= Product->SELECTION_TAB %>”
selectionColumn = “<%= lv_cellerator_selectioncolumn %>”
selectionMode = “<%= lv_cellerator_selectionmode %>”
table = “//Product/Table”
usage = “EDITLIST”
visibleFirstRow = “<%= Product->VISIBLE_FIRST_ROW_INDEX %>”
visibleRowCount = “6”
width = “100%”
xml = “<%= controller->configuration_descr->get_config_data( ) %>” />–%>
<chtmlb:configTree id = “TreeView”
nodeTable = “<%= product->node_tab %>”
dragAndDropIterator = “<%= controller->gr_drag_drop %>”
nodeTextColumn = “NODE_ID”
onCollapseNode = “collapse”
onExpandNode = “expand”
onRowSelection = “select”
selectionMode = “NONE”
selectedRowIndexTable = “<%= product->SELECTION_TAB %>”
selectedRowIndex = “<%= product->SELECTED_INDEX %>”
<%– type = “ASSIGNMENTBLOCK”–%>
downloadToExcel = “FALSE”
noFrame = “TRUE”
table = “//product/Table”
personalizable = “TRUE”
visibleRowCount = “20”
actions = “<%= controller->gt_button %>”
xml = “<%= controller->configuration_descr->get_config_data( ) %>” />
and the configuration add the fields to be displayed on the browser:-
Step5: The last step in the TREE type view creation is that we redefine DO_PREPARE_OUTPUT and in that when the view is loaded first time we’ll add only the Parent items from the ZBSP_TREE table into the collection wrapper after which we call the refresh method which will invoke the proxy class GET_CHILDREN to pick up its children.
TYPES: BEGIN OF ltype_attr_struct,
product_id TYPE zprod_id,
prod_company TYPE zprod_company,
prod_type TYPE zprod_root_type,
parent_id TYPE zprod_id,
END OF ltype_attr_struct.
DATA: lv_struct_ref TYPE REF TO ltype_attr_struct,
lv_value_node TYPE REF TO cl_bsp_wd_value_node,
lv_size_s TYPE i,
lv_size_d TYPE i,
lv_bo_coll TYPE REF TO if_bol_bo_col.
DATA: ls_tree_product TYPE ztree_product,
ls_tree_product_tmp TYPE ztree_product,
lt_tree_product TYPE ztree_product_tt.
* typed_context->product->collection_wrapper->clear_collection( ).
REFRESH lt_tree_product.
IF iv_first_time IS NOT INITIAL.
CREATE OBJECT lv_bo_coll TYPE cl_crm_bol_bo_col.
lt_tree_product[] = gt_tree_product[].
DELETE lt_tree_product WHERE parent_id IS NOT INITIAL.
LOOP AT lt_tree_product INTO ls_tree_product.
CREATE DATA lv_struct_ref.
CREATE OBJECT lv_value_node
EXPORTING
iv_data_ref = lv_struct_ref.
CALL METHOD lv_value_node->if_bol_bo_property_access~set_properties
EXPORTING
is_attributes = ls_tree_product.
lv_bo_coll->add( lv_value_node ).
ENDLOOP.
typed_context->product->collection_wrapper->set_collection( lv_bo_coll ).
typed_context->product->refresh( ).
ENDIF.
CALL METHOD super->do_prepare_output
EXPORTING
iv_first_time = iv_first_time.
Now when you test this BSP application by clicking on the button you’ll see it will look like the tree in the browser:-
Also create the events collapse and expand (EH_ONCOLLAPSE & EH_ONEXPAND) the code snippet is given below:-
METHOD eh_oncollapse.
DATA: lv_event TYPE REF TO cl_thtmlb_tree.
FIELD-SYMBOLS: <line> TYPE crmt_bsp_treetable_node.
lv_event ?= htmlb_event_ex.
typed_context->product->collapse_node( lv_event->row_key ).
ENDMETHOD.
METHOD eh_onexpand.
DATA: lv_event TYPE REF TO cl_thtmlb_tree.
FIELD-SYMBOLS: <line> TYPE crmt_bsp_treetable_node.
lv_event ?= htmlb_event_ex.
typed_context->product->expand_node( lv_event->row_key ).
ENDMETHOD.
Steps for Inclusion of Drag And Drop Feature
After we have created the tree type view now we will be discussing the steps in order to include the drag & drop functionality:-
Step1: The first step is that we need to make the changes in the HTM (View Layout) to include the drag and drop iterator for which we again need to create a class containing the method which will set the property of the view as DRAG & DROP. The screenshots are given below:-
<chtmlb:configTree id = “TreeView”
nodeTable = “<%= product->node_tab %>”
dragAndDropIterator = “<%= controller->gr_drag_drop %>”
nodeTextColumn = “NODE_ID”
onCollapseNode = “collapse”
onExpandNode = “expand”
onRowSelection = “select”
selectionMode = “NONE”
selectedRowIndexTable = “<%= product->SELECTION_TAB %>”
selectedRowIndex = “<%= product->SELECTED_INDEX %>”
<%– type = “ASSIGNMENTBLOCK”–%>
downloadToExcel = “FALSE”
noFrame = “TRUE”
table = “//product/Table”
personalizable = “TRUE”
visibleRowCount = “20”
actions = “<%= controller->gt_button %>”
xml = “<%= controller->configuration_descr->get_config_data( ) %>” />
In this class include the interface IF_THTMLB_DRAG_N_DROP_ITERATOR and there is no super class for this. After you include the interface you’ll get the methods as IF_THTMLB_DRAG_N_DROP_ITERATOR~RENDER_OBJECTS_DND_BEHAVIORS
IF_THTMLB_DRAG_N_DROP_ITERATOR~RENDER_HEADER_DND_BEHAVIORS
We’ll redefining the method IF_THTMLB_DRAG_N_DROP_ITERATOR~RENDER_OBJECTS_DND_BEHAVIORS
The code is given below:-
METHOD if_thtmlb_drag_n_drop_iterator~render_objects_dnd_behaviors.
DATA: ls_behavior TYPE crm_thtmlb_behavior_structure.
ls_behavior-behaviorid = ‘B2’. “#EC NOTEXT
ls_behavior-flavor = cl_bsp_dlc_config_util=>c_dnd_default_flavor. “‘F2’.
ls_behavior-issource = ‘X’. “#EC NOTEXT
ls_behavior-istarget = ‘X’. “#EC NOTEXT
ls_behavior-effect_cross_control = ‘MOVE’. “#EC NOTEXT
ls_behavior-effect_inside_control = ‘MOVE’. “#EC NOTEXT
APPEND ls_behavior TO ev_behavior.
Also please add the following line of code to instantiate the object of the class in DO_INIT
Step2: the last step to include the functionality is to add the interface IF_THTMLB_DRAG_N_DROP in the implementation class of the view ZL_ZBSP_TRE_PRODUCT_IMPL which will in turn add the methods IF_THTMLB_DRAG_N_DROP~ON_DRAG & IF_THTMLB_DRAG_N_DROP~ON_DROP respectively. As far as logic is concerned there is a table which is already created when you had converted the view to the tree node Context_node->Product->Node_tab which is populated by the GET_CHILDREN method depending upon you logic to populate the children. So in the drag and drop we’ll be basically playing around with this table for instance we are moving child at position 6 to 1 we’ll be just changing the parent_id for 6 with that of 1 and then in do _prepare_out put we’ll be just reinitializing the table after the table is build. The coding as well as the snapshots are given below for more reference:-
This is the internal table which we’ll using to refresh the context_node->product->node_tab
METHOD if_thtmlb_drag_n_drop~on_drag.
CONSTANTS lc_moved TYPE c VALUE ‘M’.
DATA: lr_iterator TYPE REF TO if_bol_bo_col_iterator,
lr_entity TYPE REF TO if_bol_bo_property_access,
ls_tree TYPE ztree_product,
lr_dnd_obj TYPE REF TO cl_thtmlb_table_dnd_object.
lr_dnd_obj ?= drag_n_drop_object.
CASE effect.
WHEN ‘MOVE’.
READ TABLE typed_context->product->node_tab[] INTO gs_tree_product INDEX lr_dnd_obj->row.
IF sy-subrc IS INITIAL.
DELETE typed_context->product->node_tab[] INDEX lr_dnd_obj->row.
ENDIF.
WHEN ‘COPY’.
ENDCASE.
ENDMETHOD.
METHOD if_thtmlb_drag_n_drop~on_drop.
CONSTANTS lc_moved TYPE c VALUE ‘M’.
DATA: lr_iterator TYPE REF TO if_bol_bo_col_iterator,
lr_entity TYPE REF TO if_bol_bo_property_access,
ls_tree TYPE ztree_product,
ls_tree_par TYPE ztree_product,
lv_expand_id TYPE string,
lv_row TYPE i,
lv_parent TYPE zprod_id,
ls_node_tab TYPE crmt_bsp_treetable_node,
lv_dnd_obj TYPE REF TO cl_thtmlb_table_dnd_object.
TRY.
lv_dnd_obj ?= drag_n_drop_object.
IF lv_dnd_obj->row EQ 0.
lv_dnd_obj->row = 1.
ENDIF.
IF gs_tree_product IS NOT INITIAL.
READ TABLE typed_context->product->node_tab[] INTO ls_node_tab INDEX lv_dnd_obj->row.
IF sy-subrc IS INITIAL.
IF ls_node_tab-parent_key IS NOT INITIAL.
gs_tree_product-parent_key = ls_node_tab-parent_key.
ELSE.
gs_tree_product-parent_key = ls_node_tab-node_key.
ENDIF.
INSERT gs_tree_product INTO typed_context->product->node_tab[] INDEX lv_dnd_obj->row.
gt_node_tab[] = typed_context->product->node_tab[].
ELSE.
lv_row = lv_dnd_obj->row – 1.
READ TABLE typed_context->product->node_tab[] INTO ls_node_tab INDEX lv_row.
IF sy-subrc IS INITIAL.
IF ls_node_tab-parent_key IS NOT INITIAL.
gs_tree_product-parent_key = ls_node_tab-parent_key.
ELSE.
gs_tree_product-parent_key = ls_node_tab-node_key.
ENDIF.
INSERT gs_tree_product INTO typed_context->product->node_tab[] INDEX lv_row.
gt_node_tab[] = typed_context->product->node_tab[].
ELSE.
lv_row = lv_dnd_obj->row + 1.
READ TABLE typed_context->product->node_tab[] INTO ls_node_tab INDEX lv_row.
IF sy-subrc IS INITIAL.
IF ls_node_tab-parent_key IS NOT INITIAL.
gs_tree_product-parent_key = ls_node_tab-parent_key.
ELSE.
gs_tree_product-parent_key = ls_node_tab-node_key.
ENDIF.
INSERT gs_tree_product INTO typed_context->product->node_tab[] INDEX lv_row.
gt_node_tab[] = typed_context->product->node_tab[].
ENDIF.
ENDIF.
ENDIF.
ENDIF.
CATCH cx_root.
ENDTRY.
ENDMETHOD.
Testing the working model of Drag & Drop in browser
As we are done with the development now we’ll test it in the browser:-
Run the test button
Now drag the product ID 100202 to 100102
After dragging it looks like
So its moved where we had dragged.
Good one. 🙂
Good document, more convenient for customer!
Hi Rajwin,
Good document, Keep it up 🙂 .
Regards,
Himanshu Sharma
Really Nice document, this is very helpful.
Kudos!
Deepak
Great Blog..!!
A complex requirement well structured and explained in an easy way. This helped me in clearing my concepts about the tree view and good to learn about the drag and drop functionality. Thanks a lot.
Well done. Keep going Rajwin.
Regards,
Nishant Arora
Thanks for taking time to write this blog Rajwin. It's a good one and would be helpful for SAP CRM Consultants.
Tricky one but this doc will surely make it easy . . .
Thanks for sharing 🙂
Thanks Rajwin, Its really helpful...