Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 

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.

  1. 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.

  1. 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.

8 Comments
Labels in this area