Follow by Email

Wednesday, 1 October 2014

Using Drag-Drop functionality in af:treeTable to move data between nodes -Oracle ADF

This is a very common question and development requirement - How to drag drop records inside treeTable to perform some kind of operation ?
This post is an answer,here i am using Departments and Employees table of HR Schema to create treeTable and Jdeveloper 12.1.3

First Step-
Create business components using Departments and Employees table of HR Schema and create association and viewLink using DepartmentId (here Departments is parent and Employee is child viewObject)




now drop Departments viewObject as treeTable on page from data-control
see- Tree Table Component in Oracle ADF(Hierarchical Representation)  (How to create treeTable in ADF)

So after creating simple treeTable, added  two columns other than nodeStamp to show DepartmentName and EmployeeName in a better way
see-Tree Table Component with declarative presentation in ADF

Finally it looks like this-


Now my requirement is - when drag an Employee to any Department node it should become child of that Department ,means attach Employee to Departments using drag-drop

So to drag Employee Name filed i added af:attributeDragSource under this field and to get corresponding EmployeeId added an af:clientAttribute component




This clientAttribute stores value of EmployeeId for each node and dragSource refers clientAttribute to identify node value
Now to handle dropEvent on DepatmentName node , dropped an af:dropTarget under this field and created a dropListener in managed bean that will handle desired operation on dropEvent


See complete af:treeTable xml source-

<af:treeTable value="#{bindings.Departments1.treeModel}" var="node"
                  selectionListener="#{bindings.Departments1.treeModel.makeCurrent}" rowSelection="single" id="tt1"
                  binding="#{pageFlowScope.DragDropBean.treeTabBind}">
      <f:facet name="nodeStamp">
        <af:column id="c1" width="10">
          <af:outputText value="#{node}" id="ot1"/>
        </af:column>
      </f:facet>
      <f:facet name="pathStamp">
        <af:outputText value="#{node}" id="ot2"/>
      </f:facet>
      <af:column id="c2" width="150">
        <af:outputText value="#{node.DepartmentName}" id="ot3"
                       inlineStyle="font-weight:bold;color:red;font-size:small;">
          <af:dropTarget dropListener="#{pageFlowScope.DragDropBean.treeDropListener}">
            <af:dataFlavor flavorClass="java.lang.Object"/>
          </af:dropTarget>
        </af:outputText>
      </af:column>
      <af:column id="c3">
        <af:outputText value="#{node.FirstName}" id="ot4" inlineStyle="font-weight:bold;color:darkgreen;">
          <af:clientAttribute name="DragEmployeeId" value="#{node.EmployeeId}"/>
          <af:attributeDragSource attribute="DragEmployeeId"/>
        </af:outputText>
      </af:column>
    </af:treeTable>

Now see the code of drop listener written in managed bean that gets EmployeeId value from dropEvent and DepartmentId from expression and calls a business logic to move employee under that Deaprtment

DropListener in ManagedBean to handle dropEvent-

    /**Method to move Employee Under Department
     * @param dropEvent
     * @return
     */
    public DnDAction treeDropListener(DropEvent dropEvent) {

        Object empId = null;
        Integer dropVal = null;
        //Get Value from dragSource (EmployeeId of dragged node)
        DataFlavor<Object> df = DataFlavor.getDataFlavor(Object.class);
        empId = dropEvent.getTransferable().getData(df);
        if (empId != null) {
            System.out.println("Dropped value is -" + empId);
            try {
                dropVal = new Number(empId).intValue();
            } catch (SQLException e) {
            }
            //Get DepartmentId where Employee is dropped (resolve Expression langusge)
            Object droppedUnderDept = resolvElDC("#{node.DepartmentId}");
            System.out.println("Dropped under-" + droppedUnderDept);
            //Method Call to mode Employee under Department
            OperationBinding ob = executeOperation("moveEmployeeToDepartment");
            ob.getParamsMap().put("deptId", Integer.parseInt(droppedUnderDept.toString()));
            ob.getParamsMap().put("empId", dropVal);
            ob.execute();
        }
        /*Method to expand treeTable to show all nodes
         * see-http://www.awasthiashish.com/2013/10/expand-and-collapse-aftreetable.html
         * */
        expandTreeTable();
        //Refreshing treeTable after all operation, here treeTabBind is component binding of treeTable
        AdfFacesContext.getCurrentInstance().addPartialTarget(treeTabBind);
        return DnDAction.NONE;

    }

Helper methods to get BindingContainer and resolve expression-

    /*****Generic Method to call operation binding**/
    public BindingContainer getBindingsCont() {
        return BindingContext.getCurrent().getCurrentBindingsEntry();
    }

    /**
     * Generic Method to execute operation Binding
     * */
    public OperationBinding executeOperation(String operation) {
        OperationBinding createParam = getBindingsCont().getOperationBinding(operation);
        return createParam;

    }



    /**Method to resolve Expression
     * @param data
     * @return
     */
    public Object resolvElDC(String data) {
        FacesContext fc = FacesContext.getCurrentInstance();
        Application app = fc.getApplication();
        ExpressionFactory elFactory = app.getExpressionFactory();
        ELContext elContext = fc.getELContext();
        ValueExpression valueExp = elFactory.createValueExpression(elContext, data, Object.class);
        return valueExp.getValue(elContext);
    }

Now run your application and check -
Dragged Prabhakar from Purchase Department and dropped it on Finance-

 Result-
Thanks, Happy learning :)
Download Sample App
See other post on Drag-Drop functionality- Adding Drag and Drop Functionality for collections in page fragments to create insert

No comments :

Post a Comment