Why findNodeByKeyPath() fails while reading selected rows in an af:table

This topic may looks simple for many of you. However some simple mistakes may spoil your entire day. Let me share a point that I learned recently while working with a customer. The requirements was to read all the selected rows from the multi-select table's selectionListener method defined in a managed bean. The code that is initially used for iterating over selected rows was as follows.

Wrong Implementation


 public void wrongAPIForFindingSelectedRows(SelectionEvent selectionEvent) {  
      RichTable _table = (RichTable)selectionEvent.getSource();  
      RowKeySet rks = _table.getSelectedRowKeys();  
      Iterator rksIterator = rks.iterator();  
      //Store original rowKey
      Object originalRowKey = _table.getRowKey();
      try {
         while (rksIterator.hasNext()) {  
           Object rowKey = rksIterator.next();
           _table.setRowKey(rowKey); //stamp row 
 
           //get current node object  
           JUCtrlHierNodeBinding selectedNode =  
                ((JUCtrlHierBinding)  
                ((CollectionModel)_table.getValue()).getWrappedData()).  
                    findNodeByKeyPath((List)rowKey); 
  
           if (selectedNode == null) {  
                System.out.println("selectedNode is null");  
           } else {  
                Row row = selectedNode.getRow();  
                System.out.println("selectedNode in not null" + row.getAttribute(1));  
                // Process row here .......  
           }  
      } finally {
            _table.setRowKey(originalRowKey);
      }
 }  

However the above code failed to return any value for the selected row whenever the selection falls beyond the range size(specified in the page definition file). The reason is that, by design, JUCtrlHierBinding::findNodeByKeyPath(List) API will return null if the nodes that you are trying to find are out of the current range of rows in the tree binding.

Well, now let us take a look at the right implementation(or right API). Solution is to use CollectionModel::getRowData(Object rowKey) API for reading selected nodes. This API, under the cover will go and read row directly from the underlying row set iterator(in fact this change has been introduced recently).

Right Implementation


 public void rightAPIForFindingSelectedRows(SelectionEvent selectionEvent) {  
      RichTable _table = (RichTable)selectionEvent.getSource();  
      RowKeySet rks = _table.getSelectedRowKeys();  
      Iterator rksIterator = rks.iterator();  
      while (rksIterator.hasNext()) {  
           Object rowKey = rksIterator.next();  

            //get current node object...

            //Note: No need to set row currency when you 
            //use getRowData(rowKey). 
            //This method directly fetches the row data
            //from row set iterator. 
           JUCtrlHierNodeBinding selectedNode =  
                (JUCtrlHierNodeBinding)  
                ((CollectionModel)_table.getValue()).getRowData(rowKey);  

           if (selectedNode == null) {  
                System.out.println("selectedNode == null");  
           } else {  
                Row row = selectedNode.getRow();  
                System.out.println("selectedNode in not null" + row.getAttribute(1));  
                // Process the row here ........  
           }  
      }  
 }  

Comments

Anonymous said…
Hi Jobinesh,
This is a good way of getting selected nodes, but this works only with JDev 11.1.2.1.0 (11gR2) because CollectionModel::getRowData(Object rowKey) is available in the latest Trinidad classes.
What is the solution to the issue in JDev 11.1.1.6.0 ? getRowData(Object rowKey) method is not available in 11gR1
Is it okay to get the index of the row and pass it to the available getRowData(int rowIndex)method ?
Nadejda said…
Hi...
Can you help.. I have a tree when Im update seletNode, visual is not updated. can you say why?
tHANKS

Disclaimer

The views expressed on this blog are my own and do not necessarily reflect the views of my employer.