Skip to main content

<af:setPropertyListener> not working on <af:popup> with childCreation="deferred" !

You should be careful while using <af:setPropertyListener> on <af:popup>. There is a known limitation when you use <af:setPropertyListener> with 'popupFetch' type to initialize the properties/parameters for a <af:popup>. The relevant jsf snippet may look like as shown in the following diagram.

 <af:popup id="p1" contentDelivery="lazyUncached"  
  <af:setPropertyListener from="'check'" to="#{requestScope.params}"  
  <af:dialog id="d2" title="Check">  
   <af:outputText value="Param from the caller: #{requestScope.params}"  

When you run this page, you may notice that the setPropertyListener with a popupFetch type is not getting called for the first time, and the same works without issues from next time onwards.

What goes wrong here?

Let me try to summarize the reason for this behavior. In the above jsf snippet, <af:setPropertyListener> resides inside the popup body which is not available/processed when the parent page renders for the first time because of the deferred 'child creation' settings (childCreation ="deferred") for the popup. With this deferred configuration popup body is processed when you really ask for it. Please note that, af:setPropertyListener is expected to be evaluated/processed during the Apply Request Values phase in JSF life cycle which may happen much before the Render Response phase. When user opts to view popup, reuest reaches server and JSF lifecycle starts. As there is no popup body at this stage, there is no af:setPropertyListener tag for processing at Apply Request Values phase. Later in the JSF life cycle, popup body is processed at Render Response phase. Apparently next request for showing popup may have fully processed popup body in place, and everything may work as expected at this time.

The work around solution is to use the popupFetchListener method to establish state(pass parameters) instead of <af:setPropertyListener>. If you modify the above jsf snippet as shown below, this use case will work.

 <af:popup id="p2" contentDelivery="lazyUncached"  
  <af:dialog id="d3" title="Check">  
   <af:outputText value="Param from the caller: #{requestScope.params}"  
 public class TestBean {  
  public void popupFetchAction(PopupFetchEvent popupFetchEvent) {  
   ADFContext.getCurrent().getRequestScope().put("params", "check");  

Please note that this issue is being tracked as an 'Enhancement Request' by ADF Faces team. Once this is done the above stated limitation is no longer valid.

Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post-


Makoto said…
Thanks, great post! I could solve my problem now.

Popular posts from this blog

How to set Bind Variable Values at runtime ?

In this post I'm sharing a couple of approaches for programmatically setting bind variables values at run time. This post is an attempt to explain 'When to use what ?'[ In case if you are familiar with 'Bind Variables' in ADF BC, please refer Section 5.10, Working with Bind Variables in Fusion Developer's Guide ]

1. Set the Bind Variable value using RowSet::setNamedWhereClauseParam(...)

You can use use the setNamedWhereClauseParam(...) method on the ViewObject interface (which extends oracle.jbo.RowSet) to set the value for bind variables. Please note this sets the value on default RowSet. In other words, this doesn't have any effect on the secondary RowSets that you/system generates.
ViewObject vo = am.findViewObject("EmployeesView1"); vo.setNamedWhereClauseParam("bindVarDeptId", new Number(10)); vo.executeQuery();
2. Set the Bind Variable value using ViewObject's VariableValueManager::setVariableValue(...)

VariableValueManager Ma…