Generically Setting UI Component Properties in Java Studio Creator - Part 2

This is a follow on to the my blog "Generically Setting UI Component Properties in Java Studio Creator".  Based on comments from Alex and other forum posts,  I need to update the information I gave about generically setting component properties.  My first blog technique will work for a "postback" situation, that is if you have a button to do some action then show the same page again.  In JSF 1.1, the UIViewRoot component tree is not built until after the render response.  This means neither Creator nor any other ViewHandler or PhaseListener can catch the UIViewRoot at the right time on a page that has not yet been rendered.

I asked a couple JSF experts, Jayashri Visvanathan and Matt Bohm about this issue and they proposed another solution.   This blog covers that solution.

If you're new to Java Studio Creator, get used to "binding".  Use property binding whenever you possibly can.  The JSF life cycle was designed to support "binding" and it will help you in cases like this where you feel you need to go around the life cycle.  The solution involves creating properties on the Session Bean to cover the properties you want to set for multiple components.

As an example, suppose you have a page with multiple "Text Field"s.  The page might look like this.

sample textfields

In this example, we want to initialize all the text fields to be disabled until a certain condition like a user logging in.  To accomplish this we need to create a property on the Session bean to bind to.  So add a property to the Session bean called "textFieldDisabled".  To do this, right-click on the  "Session Bean" in the Project window and choose "Add->Property".

adding property

Next, add a property of type boolean called "textFieldDisabled".

Now that we have a property to bind to, we need to bind all the Text Fields to this property.  To select all the Text Fields, drag a box around the Text Fields like this.

select all

Now you can change the "Disabled" property binding for all the selected Text Fields.  From the Property window, click on the "..." next to the "disabled" property.  The property binding dialog will be brought up and you need to choose "SessionBean1.textFieldDisabled".

property binding

Not you can manipulate the same property on all the selected components from the backing bean code.  Open the "Java" view for Page1 and go to the "prerender" method.  Where you actually put the logic to change the component properties will depend on what you are basing the change on.  If the condition for changing the properties may changed before each render, you should put the logic in "prerender".  If the condition only needs to be checked once, you can put the logic in the "init" method.  For this example, add the following code to the "prerender" method.

    public void prerender() {
        /\*\*
         \* Some logic to check for read only. For now, set to true.
         \*/
        boolean readOnly = true;

       if(readOnly) {
            this.getSessionBean1().setTextFieldDisabled(true);
        }
    }
Running the web application will show a web page that looks like this.  Notice the text fields are gray because they are disabled.

web app

Points to Remember

  • In JSF 1.1 UIViewRoot component tree is not available unless you are doing a "postback" to the same page.
  • You can bind multiple components to the same property to achieve dynamic initialization.
  • You can select multiple components in the Designer by dragging a box around the components.
  • You can change the same property for multiple components by selecting multiple components and changing the property in the Property window.

Thanks go to Alex for patience and willingness to work with us on this issue.

Cheers!
-David

Comments:

Hi David, thank you for your blog! It is really helpful information. Kind regards, Alex

Posted by Alexander on October 05, 2006 at 06:02 AM MDT #

I have the solution to the original problem. I don´t know if it is the best but it works for e so far. What i did is to create my own ViewHandler. After the renderView, it is executed the getActionURL. In that moment i have acces to the faceContext wich has the UIViewRoot with the children already in. I am able to iterate and disable components even in the first access to the page. I hope it helps for future references

Posted by Luis flores on June 05, 2007 at 06:30 AM MDT #

Thanks Luis!
Perhaps you could post your ViewHandler code for others to see.
-David

Posted by David on June 05, 2007 at 06:59 AM MDT #

Of course. I hope it helps. In the example I look for a commandButton and disable it: import java.io.IOException; import java.util.List; import java.util.Locale; import javax.faces.FacesException; import javax.faces.application.ViewHandler; import javax.faces.component.UIComponent; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; import oracle.adf.view.faces.component.core.nav.CoreCommandButton; public class EtesaViewHandler { private ViewHandler _viewHandler; public EtesaViewHandler(ViewHandler delegate){ _viewHandler = delegate; } /\*\* \* @author Luis Flores Soberón 5/05/07 \* \* En este método tenemos acceso al UIViewRoot con todos sus hijos inclusive \* en la primera llamada a la página por lo que procedemos a aplicar las \* directivas de seguridad \* \* @param facesContext \* @param string \* @return \*/ public String getActionURL(FacesContext facesContext, String string) { /\*\* Just as example we iterate over the children looking for a button named commandButton1\*/ List hijos = facesContext.getViewRoot().getChildren(); for(int i=0;i <= hijos.size() -1;i++){ UIComponent componente = (UIComponent)hijos.get(i); deshabilitaComponente("commandButton1",componente); } System.out.println(hijos); return _viewHandler.getActionURL(facesContext,string); } /\*\* Here we look if tghis component is the one. If it is not, we look into its childern\*/ private void deshabilitaComponente(String nombre, UIComponent componente){ if(componente.getId().equalsIgnoreCase(nombre)){ if(componente instanceof CoreCommandButton) ((CoreCommandButton)componente).setDisabled(true); return; } List hijos = componente.getChildren(); if(hijos == null || hijos.size() == 0) return; for(int i=0;i <= hijos.size() -1;i++){ deshabilitaComponente(nombre,(UIComponent)hijos.get(i)); } return; } /\*\* En los siguientes métodos simplemente delegamos la responsabilidad al manejador que nos llamó\*\*/ public Locale calculateLocale(FacesContext facesContext) { return _viewHandler.calculateLocale(facesContext); } public String calculateRenderKitId(FacesContext facesContext) { return _viewHandler.calculateRenderKitId(facesContext); } public UIViewRoot createView(FacesContext facesContext, String string) { return _viewHandler.createView(facesContext,string); } public String getResourceURL(FacesContext facesContext, String string) { return _viewHandler.getResourceURL(facesContext,string); } public void renderView(FacesContext facesContext, UIViewRoot uIViewRoot) throws IOException, FacesException{ _viewHandler.renderView(facesContext,uIViewRoot); } public UIViewRoot restoreView(FacesContext facesContext, String string) { return _viewHandler.restoreView(facesContext,string); } public void writeState(FacesContext facesContext) throws IOException{ _viewHandler.writeState(facesContext); } }

Posted by Luis Flores on June 05, 2007 at 08:40 AM MDT #

I'm sorry. I didn't copy the original one. In the last I forgot to include the extends clause of the class. The correct declaration of the class is the next: public class EtesaViewHandler extends ViewHandler{ Thanks

Posted by Luis Flores on June 05, 2007 at 08:45 AM MDT #

Here's a formatted version of Luis' code.
Thanks again Luis!


In the example I look for a commandButton
and disable it:





import java.io.IOException;



import
java.util.List;

import java.util.Locale;



import
javax.faces.FacesException;

import
javax.faces.application.ViewHandler;

import
javax.faces.component.UIComponent;

import
javax.faces.component.UIViewRoot;

import
javax.faces.context.FacesContext;



import
oracle.adf.view.faces.component.core.nav.CoreCommandButton;



public
class EtesaViewHandler {

    private ViewHandler _viewHandler;

   
public EtesaViewHandler(ViewHandler delegate){

        _viewHandler =
delegate;

    }



    /\*\*

     \* @author Luis Flores Soberón   
5/05/07

     \* 

     \* En este método tenemos acceso al UIViewRoot con
todos sus hijos inclusive 

     \* en la primera llamada a la página por
lo que procedemos a aplicar las 

     \* directivas de seguridad

     \*


     \* @param facesContext

     \* @param string

     \* @return

    
\*/

    public String getActionURL(FacesContext facesContext, String
string) {



	    /\*\* Just as example we iterate over the children
looking for a button named commandButton1\*/

        List hijos =
facesContext.getViewRoot().getChildren();

        for(int i=0;i <=
hijos.size() -1;i++){

            UIComponent componente =
(UIComponent)hijos.get(i);

           
deshabilitaComponente(&quot;commandButton1&quot;,componente);

       
}

        System.out.println(hijos);

        

        return
_viewHandler.getActionURL(facesContext,string);

    }

    

/\*\* Here
we look if tghis component is the one. If it is not, we look into its
childern\*/

    private void deshabilitaComponente(String nombre,
UIComponent componente){

       
if(componente.getId().equalsIgnoreCase(nombre)){

	        if(componente
instanceof CoreCommandButton)

    	       
((CoreCommandButton)componente).setDisabled(true); 

           
return;

        }

        List hijos = componente.getChildren();

    
if(hijos == null || hijos.size() == 0)

            return;

        

 
for(int i=0;i <= hijos.size() -1;i++){

           
deshabilitaComponente(nombre,(UIComponent)hijos.get(i));

        }

   
return;

    }

    /\*\* En los siguientes métodos simplemente delegamos
la responsabilidad al manejador que nos llamó\*\*/

    public Locale
calculateLocale(FacesContext facesContext) {

        return
_viewHandler.calculateLocale(facesContext);

    }



    public String
calculateRenderKitId(FacesContext facesContext) {

        return
_viewHandler.calculateRenderKitId(facesContext);

    }



    public
UIViewRoot createView(FacesContext facesContext, String string) {       


        return _viewHandler.createView(facesContext,string);

   
}



    

    public String getResourceURL(FacesContext facesContext,
String string) {

        return
_viewHandler.getResourceURL(facesContext,string);

    }



    public
void renderView(FacesContext facesContext, UIViewRoot uIViewRoot) 
throws IOException, FacesException{

       
_viewHandler.renderView(facesContext,uIViewRoot);        

    }



   
public UIViewRoot restoreView(FacesContext facesContext, String string)
{

        return _viewHandler.restoreView(facesContext,string);       


    }



    public void writeState(FacesContext facesContext) throws
IOException{

        _viewHandler.writeState(facesContext);

   
}



}

Posted by David on June 05, 2007 at 09:07 AM MDT #

I tried Luis's solution. But it seems still need a "postback" situation to work.

Posted by Grant on September 18, 2007 at 07:27 PM MDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

David Botterill

Search

Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today