ADF 11g RichFaces – creating an alternative re-parent detail records using popup and drag & drop – assigning Employees to another Department in an intuitive way

The context: ADF 11g RichFaces. Reassigning details to another master can be done in several ways. One is through the Shuttle component, another using drag and drop in trees as my colleague Luc Bors demonstrated earlier on this blog. This article discusses yet another method, which involves showing details in a popup window and dragging them from that window to their new master record. Of course I will demonstrate this functionality using Employees and Departments.

In a previous article I demonstrated how you can create a master-table detail-table page for Departments and Employees. I then added a popup window to the page, to show the Employees for the currently selected Department. The popup window can be opened from a button in the table’s toolbar. When we navigate through the departments table, the popup window is synchronized.

ADF 11g RichFaces - creating an alternative re-parent detail records using popup and drag & drop - assigning Employees to another Department in an intuitive way collectiondragndrop0000

We are going to build on top of that article and that application by adding functionality that allows the end user to select one or more Employees in the popup window and drag them to one of the Departments. By doing so, the Employees are reassigned to a new department, the model is updated and they will disàppear from the popup window they were dragged from.

Using just a few small steps leveraging the ADF 11g RichFaces drag & drop functionality, this can easily be done.

One question I have not yet solved: how can I determine what is shown during the drag operation? Right now I only get the primary key for the dragged Employee. I would like to show his picture, his name and job. But I have no clue as to how to do that.

Steps for implementing multi-row drag & drop

1. turn Employees table into a CollectionDragSource

   </af:column>
   <af:collectionDragSource modelName="emp"/>
</af:table> </af:panelWindow> </af:popup>

specify the model attribute – to connect to a specific drop target. Note that this is just a string that is used to tie source and target together – it does not refer to any bean or other object.

Specify that the table allows multi-row selection:

              <af:table partialTriggers="::DeptCollectionPanel:masterDetail1"
                        id="empTable" ...
                        rowSelection="multiple" width="746"
inlineStyle="height:164px;">

2. turn the Departments table into a CollectionDragTarget

                </af:column>
                <af:collectionDropTarget modelName="emp"/>
</af:table>

specify the same model as for the drag source

3. create a class with a method to handle the drop

public class TableDropHandler {
    public TableDropHandler() {
    }

    public DnDAction handleTableDrop(DropEvent dropEvent) {

        // dropSite will be null if dropped on the table but not on a row
        List<Key> serverRowKey = (List<Key>)dropEvent.getDropSite();
        Object stepNumber = "";
        Key dropRowKey = serverRowKey.get(0);
        DataFlavor<RowKeySet> df = DataFlavor.getDataFlavor(RowKeySet.class);
        RowKeySet droppedValue = dropEvent.getTransferable().getData(df);
        Object[] keys = droppedValue.toArray();
        oracle.jbo.domain.Number[] empKeys = new oracle.jbo.domain.Number[keys.length];
        // get the employee which we want to update the department
        for (int i = 0; i < keys.length; i++) {
              List list = (List)keys[i];
              empKeys[i] = (oracle.jbo.domain.Number)((Key)list.get(0)).getKeyValues()[0];
        }

        oracle.jbo.domain.Number newDeptno = (oracle.jbo.domain.Number)dropRowKey.getKeyValues()[0];
        return DnDAction.NONE;
    }
}

4. configure a managed bean based on this class

  <managed-bean>
    <managed-bean-name>DropHandler</managed-bean-name>
    <managed-bean-class>nl.amis.adf.TableDropHandler</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
  </managed-bean>

5. configure the drop listener for the CollectionDragTarget – connect it to the bean

                </af:column>
                <af:collectionDropTarget dropListener="#{DropHandler.handleTableDrop}"
                                         modelName="emp"/>
              </af:table>

6. provide model level method for reassigning employees to a department

To handle the assignment in the model, I have created the following method on the HrmService Application Module implementation class. It takes an array of Number objects – the empno values for the employees to be reassigned. It then uses the AllEmployeesView usage to locate each and every employee and update their Deptno attribute with the deptno value passed as the second input parameter.

    public void reassignEmpToDept(oracle.jbo.domain.Number[] empKeys, oracle.jbo.domain.Number newDeptno) {
        for (int i=0;i<empKeys.length;i++) {
            Key empKey = new Key(new Object[]{empKeys[i]});
        EmpViewRowImpl empRow =
           (EmpViewRowImpl)this.getAllEmployees().getRow(empKey);
        empRow.setDeptno(newDeptno);
        }
    }

This method is published on the client interface of the HrmService and therefore becomes exposed on the Data Control palette.

ADF 11g RichFaces - creating an alternative re-parent detail records using popup and drag & drop - assigning Employees to another Department in an intuitive way collectiondragndrop0005

7. Binding the reassign operation to the table

I have created an operation binding of this operation in the PageDefinition for my page.

    <methodAction id="reassignEmpToDept" RequiresUpdateModel="true"
                  Action="invokeMethod" MethodName="reassignEmpToDept"
                  IsViewObjectMethod="false" DataControl="HrmServiceDataControl"
                  InstanceName="HrmServiceDataControl.dataProvider">
      <NamedData NDName="empKeys" NDType="oracle.jbo.domain.Number[]"/>
      <NamedData NDName="newDeptno" NDType="oracle.jbo.domain.Number"/>
    </methodAction>
  </bindings>
</pageDefinition> 

In the DropListener method, I get hold of this operation binding, set its two parameters and invoke it. This will call the application module to update the employees selected during the drag & drop operation.

        ...
        BindingContext bcx =
            DCUtil.getBindingContext((HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest());
        JUFormBinding bc = (JUFormBinding)bcx.getCurrentBindingsEntry();
        FacesCtrlActionBinding reassignOperationBinding =
            (FacesCtrlActionBinding)bc.findControlBinding("reassignEmpToDept");
        reassignOperationBinding.getParamsMap().put("newDeptno", newDeptno);
        reassignOperationBinding.getParamsMap().put("empKeys", empKeys);
        reassignOperationBinding.invoke();

Note: at this stage these changes are in the model, but not yet submitted to the database.

To see the reassign (multi-record drag & drop) in action, run the page.

Select two employee records and drag them:

ADF 11g RichFaces - creating an alternative re-parent detail records using popup and drag & drop - assigning Employees to another Department in an intuitive way collectiondragndrop0001

When the mouse cursor hovers over a row in the Departments table, the row lights up – announcing itself as a drop target.

ADF 11g RichFaces - creating an alternative re-parent detail records using popup and drag & drop - assigning Employees to another Department in an intuitive way collectiondragndrop0002

After the drop, the two employees are gone from the Department 20 popup window

ADF 11g RichFaces - creating an alternative re-parent detail records using popup and drag & drop - assigning Employees to another Department in an intuitive way collectiondragndrop0003

When we select Department 40, we can verify in the popup Employees window that Employees have safely arrived in their destination department:

ADF 11g RichFaces - creating an alternative re-parent detail records using popup and drag & drop - assigning Employees to another Department in an intuitive way collectiondragndrop0004
 

Resources

This great article by Luc Bors on our own AMIS Weblog on dragging & dropping in rich faces Trees: Dropping Trees.

A simple, quick introduction on Drag & Drop by Duncan Mills with useful comments by Don: http://groundside.com/blog/DuncanMills.php?p=574 .

Download the JDeveloper 11g Application for this article: hrmdragndrop.zip.