31 Jan 2014

Binding Container for Declarative Component

Usually a binding container for a declarative component is provided by a page or a page fragment this component is placed on. A declarative component doesn't have its own binding container. For example, there is Main.jspx page with the following code:
    <af:form id="f1">
        <af:declarativeComponent viewId="/component.jsff" id="dc1"/> 

This page has a page definition file (representing its binding container) MainPageDef.xml:
    <iterator Binds="ViewObj" RangeSize="25" DataControl="AppModuleDataControl"
     <attributeValues IterBinding="ViewObjIterator" id="EmployeeId">
        <Item Value="EmployeeId"/>

The component.jsff page fragment looks like this:
   <af:componentDef var="attrs" componentVar="comp">
     <af:panelFormLayout id="pfl1">
        <af:inputText label="#{bindings.EmployeeId.hints.label}"
        <af:inputText  label="#{bindings.FirstName.hints.label}"
        <af:inputText  label="#{bindings.LastName.hints.label}"

So, the #{bindings} expression will return parent page's binding container and it will work if this container has EmployeeId, FirstName, LastName attribute bindings. We can decouple the declarative component from the exact Ids and pass the bindings to the component as its attributes: 

   <af:componentDef var="attrs" componentVar="comp">
        <component xmlns="http://xmlns.oracle.com/adf/faces/rich/component">
     <af:panelFormLayout id="pfl1">
        <af:inputText label="#{attrs.empId.hints.label}"
        <af:inputText  label="#{attrs.fName.hints.label}"
        <af:inputText  label="#{attrs.lName.hints.label}"

On the Main,jspx page:
<af:declarativeComponent viewId="/component.jsff" id="dc1">
 <f:attribute name="empId" value="#{bindings.EmployeeId}"/>                       
 <f:attribute name="fName" value="#{bindings.FirstName}"/>                       
 <f:attribute name="lName" value="#{bindings.LastName}"/>                       
Let's add to the declarative component a commandButton invoking a method from an application module. For sure, it would be nice to invoke an AM's method through the binding layer. And this method is always the same. It doesn't depend on where the the component is placed on. So, it'd be cool if the component had its own binding container. All we need to do is to comment the af:componentDef tag and leave only af:panelFormLayout, and afterwards we can create a pageDef file as we usually do for any page fragment or a page. If we drag-n-drop an AM's method customMethod from the Data Controls palette onto the declarative component as a commandButton, the framework will create a pageDef file componentPageDef.xml, make the changes in the DataBinding.cpx and the button will look this:
   <af:commandButton text="Button" id="dc_cb1"

Once the pageDef file is created we have to uncomment back the af:componentDef tag.

But the commandButton is not going to work, since #{bindings} expression will return parent page's binding container but not the component's one.  We can fix that using a backing bean. The ContactInfoBean class has the following methods:
//Get the component's binding container
public BindingContainer getBindings() {
    BindingContext bc = BindingContext.getCurrent();
    return bc.findBindingContainerByPath(getMyself().getViewId());        

//Get the reference to the declarative component  
public RichDynamicDeclarativeComponent getMyself() {           
    RichDynamicDeclarativeComponent  _this = 
        (RichDynamicDeclarativeComponent) getValueObject("#{comp}", RichDynamicDeclarativeComponent.class);
    return _this;

//Just a helper method for EL evaluation 
public static Object getValueObject(String expr, Class returnType){
  FacesContext fc = FacesContext.getCurrentInstance();
  ELContext elctx  = fc.getELContext();
  ExpressionFactory elFactory = fc.getApplication().getExpressionFactory();
  ValueExpression valueExpr = elFactory.createValueExpression(elctx,expr,returnType);
  return valueExpr.getValue(elctx);
The command button's declaration should be modified a little bit. We're going to add backingBeanScope.ContactInfoBean before bindings in the EL expressions:
<af:commandButton text="Button" id="dc_cb1"
And it works fine now.

The sample application for this post requires JDeveloper 11gR2.

That's it!

26 Jan 2014

ADF Faces. Immediate custom client events.

In this post I am going to focus on ADF Faces Javascript API method to fire a custom event from the client side. For example:

   function cliListener(actionEvent) {
     AdfCustomEvent.queue(actionEvent.getSource(), "servListener",
                        null, true);
We can use af:clientListener tag in order to attach the cliListener function to a command button and get the function invoked whenever the button is clicked.  On the server side we can catch the event and invoke a managed bean method:

     <af:commandButton text="TestButton" id="cb1" action="goEdit">   
      <af:clientListener type="action" method="cliListener" />
      <af:serverListener type="servListener"

The question is - what lifecycle phase is this event going to be delivered to and what phase is the managed bean method going to fire at? Sometimes it is very important because it can change the application's behavior significantly. 

Let's have a look at the specification of the AdfCustomEvent.queue method:

 * @param {AdfUIComponent} Component to queue the custom event on
 * @param {String} the type of the event
 * @param {Object} a set of parameters to include on the event.  Reserved
 *    parameter names include "type" and "immediate".
 * @param (boolean) whether the custom event is "immediate" - which will
 *  cause it to be delivered during Apply Request Values on the server,
 *  or not immediate, in which case it will be delivered during
 *  Invoke Application. 
AdfCustomEvent.queue = function(component, type, params, immediate) { ... }

I am going to focus on the immediate parameter. When its value is true, the client event is going to be delivered at the Apply Request Values phase. So, it is going to fire before command button's action and action listener methods which are going to fire at the Invoke Application phase. And if the value of the immediate parameter is false, then the client event will fire at the Invoke Application phase after command button's action and action listener methods.

Let's consider an example of a very simple task flow:
There are two view activities: BrowseView and EditView. Each of them has a PageDef file. BrowseView contains the TestButton which is described above. This button fires goEdit action, so when users click it they will go to the EditView activity. Besides that, the button click also invokes the cliListener JS function, that sends servListener custom event to the server. This event is going to be caught  and a managed bean method is going to be invoked:
 public void serverListener(ClientEvent clientEvent) {
  BindingContext bc = BindingContext.getCurrent();
  DCBindingContainer dcb = (DCBindingContainer) bc.getCurrentBindingsEntry();
  //Do something with dcb

If we set the value of the immediate parameter to true in the JS code
   function cliListener(actionEvent) {
     AdfCustomEvent.queue(actionEvent.getSource(), "servListener",
                        null, true);
then the serverListener method will be invoked at the Apply Request Values phase before going to the EditView. The name of the current binding container will be like this:


But if the immediate parameter is false, then the serverListener method will be invoked after command button's action, and the name of the current binding container will be like this:


sample application for this post requires JDeveloper R2.

Note! That all above in this post is good for R2.

In R1 the behavior is slightly different. If the command component's action causes a navigation to another view activity (like in our case) and the client event is queued with immediate=false, then the managed bean method, which is defined in the server listener, will never be invoked. But if you stay on the same view activity, then the managed bean method will be executed at the Invoke Application phase.
In case of immediate=true, the managed bean method,  defined in the server listener, will be executed anyway at the Apply Request Values phase.
That's it!