Wednesday May 30, 2012

Problem with deleting table rows using ctrl+a for row selection

The following code is commonly shown and documented for how to access the row key of selected table rows in an ADF Faces table configured for multi row selection.

public void onRemoveSelectedTableRows(ActionEvent actionEvent) {
   RichTable richTable = … get access to your table instance …
   CollectionModel cm =(CollectionModel)richTable.getValue();
   RowKeySet rowKeySet = (RowKeySet)richTable.getSelectedRowKeys();        
  
   for (Object key : rowKeySet) {
      richTable.setRowKey(key);
      JUCtrlHierNodeBinding rowData = (JUCtrlHierNodeBinding)cm.getRowData();
      // do something with rowData e.g.update, print, copy
   }
   //optional, if you changed data, refresh the table      
   AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance();
   adfFacesContext.addPartialTarget(richTable);  
   return null;
}

The code shown above works for 99.5 % of all use cases that deal with multi row selection enabled ADF Faces tables, except for when users use the ctrl+a key to mark all rows for delete. Just to make sure I am clear: if you use ctrl+a to mark rows to perform any other operation on them – like bulk updating all rows for a specific attribute – then this works with the code shown above. Even for bulk row delete, any other mean of row selection (shift+click and multiple ctrl+click) works like a charm and the rows are deleted.

So apparently it is the use of ctrl+a that causes the problem when deleting multiple rows of an ADF Faces table. To implement code that works for all table selection use cases, including the one to delete all table rows in one go, you use the code shown below.

public void onRemoveSelectedTableRows(ActionEvent actionEvent) {
  RichTable richTable = … get access to your table instance …
  CollectionModel cm = (CollectionModel)richTable.getValue();
  RowKeySet rowKeySet = (RowKeySet)richTable.getSelectedRowKeys();

  Object[] rowKeySetArray = rowKeySet.toArray();   

  for (Object key : rowKeySetArray){           
    richTable.setRowKey(key);
    JUCtrlHierNodeBinding rowData = (JUCtrlHierNodeBinding)cm.getRowData();                           
    rowData.getRow().remove();
  }
  
  AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance();          
  adfFacesContext.addPartialTarget(richTable);
}

Solving File Upload Cancel Issue

In Oracle JDeveloper 11g R1 (I did not test 11g R2) the file upload component is submitted even if users click a cancel button with immediate="true" set. Usually, immediate="true" on a command button by-passes all modle updates, which would make you think that the file upload isn't processed either. However, using a form like shown below, pressing the cancel button has no effect in that the file upload is not suppressed.

Update Aug 29/2012: Appears that all the af:subform suggestions in the original blog entry did not work out for any who tried it. The form still appears to be submitted as a whole. To effectively cancel an upload form, use the af:goButton or af:goLink as the cancel button or lnk, which does not submit the form at all.

Tuesday May 29, 2012

Common mistake when iterating rows

In a blog entry from 2010, Oracle's Jobinesh Purushothaman writes about exceptions that are getting raised after developers iterate the collection of a RichTable instance using calls to setRowKey(key).

http://jobinesh.blogspot.co.uk/2010/02/common-mistake-while-iterating-through.html

The reason for the exception is that the selected row state is change on the table without synchronization to happen with the ADF binding layer. The failure of synchronizing the table selected row state with the ADF binding layer is because no row selection event is raised on the table if the row currency is changed programmatically. In theory, if you call #{bindings.treebinding.treeModel.makeCurrent}using a method expression in EL

The failed binding synchronization is because no row selection event is fired when the selected row state is changed on the table using Java in a managed bean.

A solution to this problem could be to call #{bindings.treebinding.treeModel.makeCurrent}from a method expression in Java each time you called setRowKey(key). But, assuming the iteration of rows in a table is for aggregating numeric values or to compare two rows, do you really want to change the current row in the ADF binding layer for each row you need to access?

A better implementation for this use case in my opinion is to read the data from the ADF binding layer instead of the RichTable table instance, which then will not change the row currency at all.

RichTable table = ... get table reference ...
Iterator iter = selectedRowKeys.iterator();
CollectionModel model = (CollectionModel ) table.getValue();
JUCtrlHierBinding treeBinding = (JUCtrlHierBinding )model.getWrappedData();
if (iter != null && iter.hasNext()) {
  Object rowKey = iter.next();
  JUCtrlHierNodeBinding rowData = treeBinding.findNodeByKeyPath(rowKey);     
  //Do something here

}

Note that the reported problem in Jobinesh's blog is for ADF bound tables configured for single row selection. Still I would prefer my approach over changing the selected row state on a table.


Friday May 11, 2012

Guess What - We Want You!

Grant Ronald and the team are looking for help. Grant put the following job posting out on the Internet today

The ADF Product Management team are looking for a strong ADF technologist to join people like Frank Nimphius, Chris Muir and Lynn Munsinger as part of the ADF Product Management team tasked with ensuring customers are able to successfully adopt and implement ADF applications.

Full details of the job post can be found from the link below, or search on IRC1793732 at
https://irecruitment.oracle.com/

https://irecruitment.oracle.com/OA_HTML/OA.jsp?page=/oracle/apps/irc/candidateSelfService/webui/VisVacDispPG&akRegionApplicationId=821&transactionid=30911342&retainAM=Y&addBreadCrumb=S&p_svid=1793732&p_spid=1846054&oapc=8&oas=6vQ7kqKngmX1WWhMqxxszQ
..

For this role we are primarily looking for the role to be US based.


If you feel you have the ADF skills, knowledge and desire to help others be successful with ADF then I look forward to your application.

I see Chris Muir, who recently joined our team, still smiling: So I am convinced this offer is a good one.

Frank

Tuesday May 08, 2012

Managing component value state correctly

A frequent problem reported on OTN is about failure in saving component values using managed beans especially when multi-select components are used. Usually the problem arises when developers store select choice components values in managed beans they use for JSF component bindings as well (which then makes the managed bean becoming a backing bean). Backing beans however are saved in request scope (at least they should to not err again).

Request scope beans however reset their state after each request, which means that no user update in a select component is persisted beyond the request. The result is that user changes are not displayed in the UI or value change listeners don't execute.The proper way of handling the combination of backing beans and component values saved in a managed bean is to come up with a strategy in which the component value is written to a separate bean in a broader scope (I usually recommend viewScope) than the backing bean. The backing bean (request scope) would then access the bean in the larger scope using a ValueExpression or managed bean property to access the user selected data.

I was about to write this solution up in more detail but then found the following blog entry by Duncan Mills:

https://blogs.oracle.com/groundside/entry/the_uimanager_pattern

In his The UIManager Pattern blog entry, Duncan documented the same problem from a different angle. The programmer mistake Duncan observed was that component binding references (the Bindings property reference on an ADF Faces component) were stored in managed beans with a scope larger than request, which JavaServer Faces component don't support.

 In his write-up Duncan documents the same strategy I was about to document, which is to separate the value saving from the component reference using different managed beans in different scope. Well, I think that Duncan's blog entry saved me some time I today.

Friday May 04, 2012

Scope object serialization failed (object not serializable)

A common reason for the "SEVERE: ADFc: Scope object serialization failed (object not serializable)" error message is that application developers reference JSF components in managed beans with a scope larger than request. When using the JSF component Binding property to point to a managed bean, think backing bean and thus don't reference beans that are in scopes larger than request scope (don't: viewScope, pageFlowSope, sessionScope, applicationScope).

If, from a managed bean in a scope larger than request you need to have access to a component instance (though the other way around is a more common use case) then either

As mentioned, a more common use case is to access a bean in a scope larger than request from a backing bean. A use case for this is if you need to remember a specific state, like a list of selected values in a select many list, or the disclosure state of panel tabs.

In this case you would save the state information in a bean with a lifecycle that spans beyond request scope and access it from a request scope backing bean using a managed property or by resolving EL in Java.

About

The Oracle JDeveloper forum ranks in the Top 5 of the most active forums on the Oracle Technology Network (OTN).



The OTN Harvest blog is a summary of selected topics posted on the OTN Oracle JDeveloper forum.



It is an effort to turn knowledge exchange into an interesting read for developers who enjoy little nuggets of wisdom





Frank Nimphius

Search

Archives
« May 2012 »
SunMonTueWedThuFriSat
  
1
2
3
5
6
7
9
10
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
31
  
       
Today