Making processes more user-friendly is the challenge we are facing today and tomorrow. A nice way to make processes more user-friendly is by making them easier to work with, easier to understand and present everything as appealing and easy as possible to the end-user.
I stumbled upon this "hidden" feature whilst looking for a new and easy solution for Product Portfolio Management/Maintenance. I call it a hidden feature because when searching for it I found .... nothing But undocumented features aren't that exceptional and that's why SCN is here of course!
I think this is a Enhancement Pack 1 feature which might only be available when a particular business function is activated.
This behavior should also work for a TreeView but I didn't test that (yet).
The example below is a very basic example with no goal, I used it of course in another context but I made the example as generic as possible. In this way it's easy reproducible and the focus is on the actual drag and drop.
We'll create one Z component containing one viewset with two views. We'll drag-and-drop some data between the SOURCE view and the TARGET view.
Create Z Component
Add a Model to your component
In order to be able to add Model Context Nodes you must specify a Model in the Rutime Repository. Since I'm working with products I'll add the PROD_ALL Model.
Create the SOURCE and TARGET View
Add two Views to your Component. I added one Model Context Node on both views called PRODUCTS which are using the Product BOL Object.
I created both views as "Table View" with the options shown above. The Configurable is usefull and speeds up the process of creating the table; the "With Toolbar" is certainly not needed in this example.
The Table View will be linked to the Context Node Products as shown in the picture.
At this moment your component should look like this:
Add ViewSet to Window and the Views to the ViewSet in the Runtime Repository
Afterwards the Runtime Repository of your component should look like this:
Create an empty Class to implement the drag-and-drop behaviour for the UI element
This class will serve as the "dragAndDropIterator" iterator that is attached to the UI element. In this class we'll tell the system how we want to implement drag-and-drop.
- Create an empty class and add the IF_THTMLB_DRAG_N_DROP_ITERATOR Interface
- This enables two methods
Implement the following code in 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'. "#EC NOTEXT
LS_BEHAVIOR-ISSOURCE = 'X'. "#EC NOTEXT
LS_BEHAVIOR-ISTARGET = 'X'.
LS_BEHAVIOR-EFFECT_CROSS_CONTROL = 'MOVE'. "#EC NOTEXT
LS_BEHAVIOR-EFFECT_INSIDE_CONTROL = 'COPY'. "#EC NOTEXT
APPEND LS_BEHAVIOR TO EV_BEHAVIOR.
Prepare the SOURCE view for drag-and-drop
Make sure the table gets some data, I did a simple Query in the DO_PREPARE_OUTPUT method in the controller to fill the PRODUCTS Context Node.
- Add the Interface IF_THTMLB_DRAG_N_DROP tot the Controller Class
- This enables two methods in the class:
- Implement the following code in method IF_THTMLB_DRAG_N_DROP~ON_DRAG
DATA: LR_ITERATOR TYPE REF TO IF_BOL_BO_COL_ITERATOR,
LR_ENTITY TYPE REF TO if_bol_bo_property_access,
LR_DND_OBJ TYPE REF TO CL_THTMLB_TABLE_DND_OBJECT.
LR_DND_OBJ ?= DRAG_N_DROP_OBJECT.
LR_ITERATOR = MODEL->COLLECTION_WRAPPER->IF_BOL_BO_COL~GET_ITERATOR( ).
LR_ENTITY ?= LR_ITERATOR->GET_BY_INDEX( IV_INDEX = LR_DND_OBJ->ROW ).
LR_DND_OBJ->IF_THTMLB_DRAG_N_DROP_OBJECT~OBJECT = LR_ENTITY.
MODEL->COLLECTION_WRAPPER->IF_BOL_BO_COL~REMOVE( LR_ENTITY ).
- Add an Attribute to the Context Node PRODUCTS and reference it to the Class you created earlier
We'll use this attribute in the View later on.
- Override the IF_BSP_MODEL~INIT method in the Context Node PRODUCTS to initialize the Attribute
CALL METHOD SUPER->IF_BSP_MODEL~INIT EXPORTING ID = ID OWNER = OWNER . CREATE OBJECT GR_DND_ITERATOR.
- Go to the View Layout
Add the "dragAndDropIterator" (Case sensitive!) attribute to the configCellerator and reference it to the Attribute you just created in your Context Node.
Prepare the TARGET view for drag-and-drop
Basically, do exactly the same as for the SOURCE view with the only exception to implement the ON_DROP method to make sure it's able to receive dragged elements from the SOURCE view.
Implement the following in the IF_THTMLB_DRAG_N_DROP~ON_DROP method of the Controller class:
DATA: LR_ITERATOR TYPE REF TO IF_BOL_BO_COL_ITERATOR, LR_ENTITY TYPE REF TO IF_BOL_BO_PROPERTY_ACCESS, LV_DND_OBJ TYPE REF TO CL_THTMLB_TABLE_DND_OBJECT. TRY. LV_DND_OBJ ?= DRAG_N_DROP_OBJECT. LR_ENTITY ?= LV_DND_OBJ->IF_THTMLB_DRAG_N_DROP_OBJECT~OBJECT. IF LV_DND_OBJ->ROW EQ 0. LV_DND_OBJ->ROW = 1. ENDIF. MODEL->COLLECTION_WRAPPER->INSERT( IV_BO = LR_ENTITY IV_INDEX = LV_DND_OBJ->ROW ). CATCH CX_ROOT. ENDTRY.
You should get something like in the video below:
Unfortunately you can only drop on a table which already contains data... If the table is empty you cannot drop anything onto it.