Thursday, November 4, 2010

ADF UI - Implementing multi-select table (Selecting and processing multiple rows)

When it comes to implementation of multi-select table using Oracle ADF, it'll become little tricky. In this post, I'll explain how easily we can select multiple rows from af:table and process them for whatever need you have.

For example, let's take Employee search screen and from the search results table, let's select multiple employee records and click on 'Delete' button to delete the selected employee records. You can download the sample application from here. Please follow the below mentioned steps:

1. Drag and drop the VO as af:table into the jsff page and from the source remove the properties 'selectedRowKeys' and 'selectionListener'. And set 'rowSelection=multiple'. This will allow us to select multiple rows. You can select the multiple rows by clicking multiple rows pressing 'Ctrl' key or you can do the range selection by pression 'Shift' key.

2. Now, add a binding for the af:table as a bean property. And, write an actionListener method for the 'Delete' button to invoke after selecting multiple rows.

After doing this, the table code would look like this: 
<af:table value="#{bindings.EmpDeptVO.collectionModel}" var="row" rows="#{bindings.EmpDeptVO.rangeSize}" emptyText="#{bindings.EmpDeptVO.viewable ? 'No data to display.' : 'Access Denied.'}" fetchSize="#{bindings.EmpDeptVO.rangeSize}" rowBandingInterval="0" rowSelection="multiple" id="t1" partialTriggers=":::qryId1 ::ctb1" columnStretching="column:c1" styleClass="AFStretchWidth" columnSelection="multiple" first="0" contentDelivery="immediate" autoHeightRows="10" binding="#{pageFlowScope.ExampleBean.searchResultsTable}">

The bean class having ActionListener method and the table binding:
package com.demo.ui.bean; import com.mpapana.bean.ADFUtil; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.faces.event.ActionEvent; import oracle.adf.model.binding.DCBindingContainer; import oracle.adf.view.rich.component.UIXTable; import oracle.adf.view.rich.component.rich.data.RichTable; import oracle.binding.OperationBinding; public class ExampleBean { private RichTable searchResultsTable; public void setSearchResultsTable(RichTable searchResultsTable) { this.searchResultsTable = searchResultsTable; } public RichTable getSearchResultsTable() { return searchResultsTable; } public void deleteSelectedRows(ActionEvent ae) { //getting table reference from binding UIXTable table = getSearchResultsTable(); //getting iterator to iterate over selected row keys Iterator selection = table.getSelectedRowKeys().iterator(); List rowIndexes = new ArrayList(); while (selection.hasNext()) { Object rowKey = selection.next(); //setting the rowKey to table one by one table.setRowKey(rowKey); int index = table.getRowIndex(); //adding selected row indexes to a List rowIndexes.add(index); System.out.println(".... Row row=" + table.getRowData() + "\t" + index); } DCBindingContainer bindings = (DCBindingContainer)ADFUtil.evaluateEL("#{bindings}"); //getting operation binding reference to the AMImplMethod deleteSelectedRows() OperationBinding opBinding = bindings.getOperationBinding("deleteSelectedRows"); //passing the selected row keys list to the AMImpl method opBinding.getParamsMap().put("selectedRowIndexes", rowIndexes); opBinding.execute(); } }

In the above bean method deleteSelectedRows, we're getting the selected row keys and iterating over them and setting the row key to the table. We're doing this because, we hae to store te the table's row index in a list and this list will passed to the AMImpl method where the actual processing the rows is done.

4. Write a method in AMImpl (deleteSelectedRows) which takes the List selectedRowIndexes as an argument. This method iterates over the selected row indeces and gets the row at the selected index and performs either update or delete on that row (which represents the selected row in the UI table).
public void deleteSelectedRows(List selectedRowIndexes) { ViewObjectImpl empDeptVO = this.getEmpDeptVO(); for (int i = 0; i < selectedRowIndexes.size(); i++) { //getting the selected row index one by one int selectedRowIndex =(Integer) selectedRowIndexes.get(i); //setting the current row to the row at selected index empDeptVO.setCurrentRowAtRangeIndex(selectedRowIndex); //deleting the current row empDeptVO.removeCurrentRow(); } //committing the transaction this.getTransaction().commit(); }

Suppose, if you need to update the rows, sample code below:
public void updateSelectedRows(List selectedRowIndexes) { ViewObjectImpl empDeptVO = this.getEmpDeptVO(); for (int i = 0; i < selectedRowIndexes.size(); i++) { //getting the selected row index one by one int selectedRowIndex =(Integer) selectedRowIndexes.get(i); //setting the current row to the row at selected index empDeptVO.setCurrentRowAtRangeIndex(selectedRowIndex); Row row = empDeptVO.getCurrentRow(); //updating the Ename attribute row.setAttribute("Ename", row.getAttribute("Ename") + "+"); } //committing the transaction this.getTransaction().commit(); }


5. The same AMImpl method will be invoked from the bean method (refer to: how to invoke AMImpl method in bean) the selected rows will be deleted and the transaction is committed in the AMImpl's method.

That's it. In a nut shell, the bean method will store selected row indexes in a list and the AMImpl method takes that list and does the operations (update or delete) on the rows at those selected indexes.

Sample screen shots:
1. Select two records 'SCOTT' and 'JAMES' and click 'Delete'.
 2. Search again. The two records got deleted and won't appear in search results.

Enjoy :) !

4 comments:

  1. Hi all ,
    In my project i need to select multiple rows from a table.

    The code i have tried using after looking forum are as below:-


    ==========
    1. RowKeySet selectRegion=getReAssignUserToLocationTable().getSelectedRowKeys();
    Iterator itr=selectRegion.iterator();
    DCBindingContainer binding=(DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
    DCIteratorBinding reg=binding.findIteratorBinding("accountContactsIterator");
    RowSetIterator rtr=reg.getRowSetIterator();
    System.out.println("setting value"+rtr);
    while(itr.hasNext()){
    System.out.println("inside loop");
    Key key=(Key)((List)itr.next()).get(0);
    System.out.println("inside loop2"+key); // till this point its working good
    Row currentRow = rtr.getRow(key); // fetching null at this stage
    System.out.println("inside loop3"+currentRow);
    ===> System.out.println(currentRow.getAttribute("LNAccountSeqId")); // due to above line fetching null we getting "null pointer exception"

    }
    =======================================
    In the above method i am getting "null pointer exception" at marked step( ==>), after debugging i came to know that the iterator from where i am trying to fetch row data is returning null while quering with row key inside the loop. "we are not using VIEW OBJECT in our project because of which above code is not working for us. we are using "non ADF iterator and jaxp java classes" to call the webservice.
    in the above code we are able to populate rowkeys set and able to print the keys value for the rows we selecting from table.

    ==> need your help in order to fetch data of a selected row inside while loop for a key. kindly assist.

    -==================================
    And another option we tried is below, In this we are using only table to get keys and fetching data from the row but this also getting null pointer exception at marked row (====>),
    i am not understanding why for this method also i am getting same error ???
    =====================================
    :-
    2. RowKeySet rowKeys = reAssignUserToLocationTable.getSelectedRowKeys();
    CollectionModel cm =(CollectionModel)reAssignUserToLocationTable.getValue();
    System.out.println(rowKeys);
    Object oldRowKey = reAssignUserToLocationTable.getRowKey();
    try{
    for (Object rowkey:rowKeys) {
    System.out.println("inside for loop");
    int i =rowkey.hashCode();
    System.out.println(" i = " +i);
    System.out.println("row data is "+rowkey);


    reAssignUserToLocationTable.setRowKey(rowkey);
    System.out.println("index="+i);
    System.out.println("row"+ reAssignUserToLocationTable.getRowCount());// working fine till this point
    Row r= (Row)reAssignUserToLocationTable.getrow; // fetching null
    =====> System.out.println("row fetched"+ r.getAttribute("LNAccountSeqId")); // due to above line fetching null we getting " null pointer exception'"


    }
    }
    finally{
    //Restore the original rowKey
    reAssignUserToLocationTable.setRowKey(oldRowKey);
    }
    ==========================================
    waiting for valuable suggestion !
    thanks
    mohit

    ReplyDelete
  2. Can you explain the need of the following lines:

    //setting the rowKey to table one by one
    39 table.setRowKey(rowKey);

    ReplyDelete

Related Posts with Thumbnails