You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by koshi <ko...@ya.com> on 2006/12/02 19:37:14 UTC

Newbie question: How to generate a jsf component dynamically

I have a managed bean with a method that returns a UIComponent,
sometimes a commandLink or a outputText.

public UIComponent getComponent ()
{
       UIComponent link ;
       if (this.isAction ()) {
               link = new HtmlCommandLink ();
               link.setTitle (this.title);
        
               MethodBinding method = FacesContext.getCurrentInstance
().getApplication ().
                                    createMethodBinding (this.value, null);
               link.setAction (method);
       }
       else {
               link = new HtmlOutputText ();
               link.setValue (this.title);
       }

        return link;
}


Then, in the view i imagine something like that
:

<t:component value="#{managedBean.component}" />

is this possible or i have to create a custom component ???


thanks in advance, and sorry for my english mistakes.
-- 
View this message in context: http://www.nabble.com/Newbie-question%3A-How-to-generate-a-jsf-component-dynamically-tf2743954.html#a7655989
Sent from the MyFaces - Users mailing list archive at Nabble.com.


Re: Newbie question: How to generate a jsf component dynamically

Posted by Craig McClanahan <cr...@apache.org>.
On 12/3/06, Craig McClanahan <cr...@apache.org> wrote:
>
>
>
> On 12/3/06, Simon Kitching <si...@rhe.co.nz> wrote:
>
> > How would you recommend an app do this on first render of a page (eg
> > "when user setting is X, add this component else add that component")?
> > Perhaps in a binding setter method?
>
>
> That's where I would use Shale :-).  The prerender() method is the perfect
> place to put that kind of logic.  Indeed, that's what the SQL browser does
> -- it performs the query and rebuilds the children of the table component in
> the prerender() method.  Shale guarantees to call this on the first call or
> on a callback, so you don't have to do anything special.
>

I should be a little bit more verbose, and mention that I'm talking about
the "View Controller" feature of Shale[1].  It's a very lightweight
framework that gives you event callbacks on things of interest to an
application, as opposed to the low level UI events that standard JSF
processing supports.  You'll also note that the programming model supported
by View Controller is very similar to that provided by default in Java
Studio Creator, meaning it's been heavily used for a couple of years now,
and found to be quite flexible.

Craig

[1] http://shale.apache.org/shale-view/index.html

Re: Newbie question: How to generate a jsf component dynamically

Posted by Craig McClanahan <cr...@apache.org>.
On 12/3/06, Simon Kitching <si...@rhe.co.nz> wrote:
>
> Craig McClanahan wrote:
> >
> >
> > On 12/3/06, *Simon Kitching* <simon.kitching@rhe.co.nz
> > <ma...@rhe.co.nz>> wrote:
> >
> >     Hi Koshi,
> >
> >     Generally, having the component tree vary dynamically is not done
> with
> >     JSF. If you want a choice of two different components, then
> typically
> >     you define both of them in the page, then use the "rendered"
> >     property to
> >     ensure that only the one you want is output.
> >
> >     There is certainly no JSF tag in standard JSF or Tomahawk that
> allows a
> >     random component to be inserted into the tree. I don't initially see
> why
> >     it wouldn't be possible to do this, but it certainly isn't common
> JSF
> >     practice AFAIK.
> >
> >
> > I don't know about your definition of "common", but the fact that you
> > *can* construct component trees dynamically is one of the most powerful
> > features of JSF.  Consider, for example, the "shale-sql-browser" example
> > app[1] in Shale, which performs SQL queries, then looks at the JDBC
> > metadata that is returned, and builds dynamically the column components
> > inside a table component.  It's really easy to do (and this is all
> > standard JSF stuff, not dependent on Shale).
>
> Thanks for the correction Craig; I should have been more careful in my
> use of "common". And I should not have said dynamic components are
> "generally..not done with JSF"; it's just that in the current project
> I'm working on, people have several times struck problems with issues
> related to component-bindings and their initial attempt to work around
> it has often included attempts to dynamically modify the component tree
> when simpler alternatives were available.
>
> For simple cases, however, don't you think that using the "rendered"
> property to select one of a small set of components to render would be
> appropriate, rather than dynamic component creation? JSF supports
> "templating" of presentation (jsp, facelets, clay, etc) in order to push
> most of the layout issues out of java code...


If the set of components you might want to expose is deterministic (i.e. the
choice is "show this set or not" versus "construct a set that corresponds to
my data") this can work, although you have to be sensitive to how many
components you have in the tree that are not being displayed, but still
having to be processed through all the lifecycle phases.

The only problems I've ever had with dynamic component trees relate to using
JSF 1.1 and JSP together, because in that environment the component tree
gets built dynamically (the first time only), and you can't make forward
references.  If you use Clay or Facelets with JSF 1.1, or use any view
handler with JSF 1.2, you don't have to worry about that.


>
> >
> >     If you *did* want to create such a component, I can imagine one that
> has
> >     a single child; on encodeBegin it evaluates its value expression,
> sets
> >     that component as its child then passes on the encodeBegin call. All
> >     other component methods would get delegated down to the child as
> normal.
> >
> >
> > It's easier to compose the component tree in an action event handler ...
> > saves all the extra effort needed to define and register a component.
> >
>
> Yes, following a postback a managed bean action method can access a
> component on the page (using binding or lookup) then explicitly add
> children to it to create dynamically-generated page sections.
>
> How would you recommend an app do this on first render of a page (eg
> "when user setting is X, add this component else add that component")?
> Perhaps in a binding setter method?


That's where I would use Shale :-).  The prerender() method is the perfect
place to put that kind of logic.  Indeed, that's what the SQL browser does
-- it performs the query and rebuilds the children of the table component in
the prerender() method.  Shale guarantees to call this on the first call or
on a callback, so you don't have to do anything special.

Without Shale, it is not uncommon to see this kind of thing done in the
constructor of a managed bean, although this can cause you some grief
because the bean itself hasn't been registered in request scope yet (while
the constructor is running).  Using binding setter methods can be
problematic because you can't control the timing versus the creation of
other components, and you can't necessarily be assured it will be called
only once.


Craig


Regards,
>
> Simon
>

Re: Newbie question: How to generate a jsf component dynamically

Posted by Simon Kitching <si...@rhe.co.nz>.
Craig McClanahan wrote:
> 
> 
> On 12/3/06, *Simon Kitching* <simon.kitching@rhe.co.nz 
> <ma...@rhe.co.nz>> wrote:
> 
>     Hi Koshi,
> 
>     Generally, having the component tree vary dynamically is not done with
>     JSF. If you want a choice of two different components, then typically
>     you define both of them in the page, then use the "rendered"
>     property to
>     ensure that only the one you want is output.
> 
>     There is certainly no JSF tag in standard JSF or Tomahawk that allows a
>     random component to be inserted into the tree. I don't initially see why
>     it wouldn't be possible to do this, but it certainly isn't common JSF
>     practice AFAIK.
> 
> 
> I don't know about your definition of "common", but the fact that you 
> *can* construct component trees dynamically is one of the most powerful 
> features of JSF.  Consider, for example, the "shale-sql-browser" example 
> app[1] in Shale, which performs SQL queries, then looks at the JDBC 
> metadata that is returned, and builds dynamically the column components 
> inside a table component.  It's really easy to do (and this is all 
> standard JSF stuff, not dependent on Shale).

Thanks for the correction Craig; I should have been more careful in my 
use of "common". And I should not have said dynamic components are 
"generally..not done with JSF"; it's just that in the current project 
I'm working on, people have several times struck problems with issues 
related to component-bindings and their initial attempt to work around 
it has often included attempts to dynamically modify the component tree 
when simpler alternatives were available.

For simple cases, however, don't you think that using the "rendered" 
property to select one of a small set of components to render would be 
appropriate, rather than dynamic component creation? JSF supports 
"templating" of presentation (jsp, facelets, clay, etc) in order to push 
most of the layout issues out of java code...

> 
> 
>     If you *did* want to create such a component, I can imagine one that has
>     a single child; on encodeBegin it evaluates its value expression, sets
>     that component as its child then passes on the encodeBegin call. All
>     other component methods would get delegated down to the child as normal.
> 
> 
> It's easier to compose the component tree in an action event handler ... 
> saves all the extra effort needed to define and register a component.
> 

Yes, following a postback a managed bean action method can access a 
component on the page (using binding or lookup) then explicitly add 
children to it to create dynamically-generated page sections.

How would you recommend an app do this on first render of a page (eg 
"when user setting is X, add this component else add that component")? 
Perhaps in a binding setter method?

Regards,

Simon

Re: Newbie question: How to generate a jsf component dynamically

Posted by Craig McClanahan <cr...@apache.org>.
On 12/3/06, Simon Kitching <si...@rhe.co.nz> wrote:
>
> Hi Koshi,
>
> Generally, having the component tree vary dynamically is not done with
> JSF. If you want a choice of two different components, then typically
> you define both of them in the page, then use the "rendered" property to
> ensure that only the one you want is output.
>
> There is certainly no JSF tag in standard JSF or Tomahawk that allows a
> random component to be inserted into the tree. I don't initially see why
> it wouldn't be possible to do this, but it certainly isn't common JSF
> practice AFAIK.


I don't know about your definition of "common", but the fact that you *can*
construct component trees dynamically is one of the most powerful features
of JSF.  Consider, for example, the "shale-sql-browser" example app[1] in
Shale, which performs SQL queries, then looks at the JDBC metadata that is
returned, and builds dynamically the column components inside a table
component.  It's really easy to do (and this is all standard JSF stuff, not
dependent on Shale).


If you *did* want to create such a component, I can imagine one that has
> a single child; on encodeBegin it evaluates its value expression, sets
> that component as its child then passes on the encodeBegin call. All
> other component methods would get delegated down to the child as normal.


It's easier to compose the component tree in an action event handler ...
saves all the extra effort needed to define and register a component.

Regards,
>
> Simon



Craig

[1] http://people.apache.org/builds/shale/nightly/



koshi wrote:
> > I have a managed bean with a method that returns a UIComponent,
> > sometimes a commandLink or a outputText.
> >
> > public UIComponent getComponent ()
> > {
> >        UIComponent link ;
> >        if (this.isAction ()) {
> >                link = new HtmlCommandLink ();
> >                link.setTitle (this.title);
> >
> >                MethodBinding method = FacesContext.getCurrentInstance
> > ().getApplication ().
> >                                     createMethodBinding (this.value,
> null);
> >                link.setAction (method);
> >        }
> >        else {
> >                link = new HtmlOutputText ();
> >                link.setValue (this.title);
> >        }
> >
> >         return link;
> > }
> >
> >
> > Then, in the view i imagine something like that
> > :
> >
> > <t:component value="#{managedBean.component}" />
> >
> > is this possible or i have to create a custom component ???
> >
> >
> > thanks in advance, and sorry for my english mistakes.
>
>

Re: Newbie question: How to generate a jsf component dynamically

Posted by Simon Kitching <si...@rhe.co.nz>.
Hi Koshi,

Generally, having the component tree vary dynamically is not done with 
JSF. If you want a choice of two different components, then typically 
you define both of them in the page, then use the "rendered" property to 
ensure that only the one you want is output.

There is certainly no JSF tag in standard JSF or Tomahawk that allows a 
random component to be inserted into the tree. I don't initially see why 
it wouldn't be possible to do this, but it certainly isn't common JSF 
practice AFAIK.

If you *did* want to create such a component, I can imagine one that has 
a single child; on encodeBegin it evaluates its value expression, sets 
that component as its child then passes on the encodeBegin call. All 
other component methods would get delegated down to the child as normal.

Regards,

Simon

koshi wrote:
> I have a managed bean with a method that returns a UIComponent,
> sometimes a commandLink or a outputText.
> 
> public UIComponent getComponent ()
> {
>        UIComponent link ;
>        if (this.isAction ()) {
>                link = new HtmlCommandLink ();
>                link.setTitle (this.title);
>         
>                MethodBinding method = FacesContext.getCurrentInstance
> ().getApplication ().
>                                     createMethodBinding (this.value, null);
>                link.setAction (method);
>        }
>        else {
>                link = new HtmlOutputText ();
>                link.setValue (this.title);
>        }
> 
>         return link;
> }
> 
> 
> Then, in the view i imagine something like that
> :
> 
> <t:component value="#{managedBean.component}" />
> 
> is this possible or i have to create a custom component ???
> 
> 
> thanks in advance, and sorry for my english mistakes.


Re: Newbie question: How to generate a jsf component dynamically

Posted by Simon Kitching <si...@rhe.co.nz>.
And this probably doesn't help:
   link.setId (action.getId ());

Here the link is given an identical id to the parent, but ids must be 
unique.  Try something like "link.setId(action.getId() + "_link");

David Delbecq wrote:
> Those calls (and other components you may create) are wrong:
>        HtmlPanelGrid grid = new HtmlPanelGrid ();
>        HtmlCommandLink link = new HtmlCommandLink ();
> 
> To create component, use the FacesContext.getApplication().createComponent(componentType) call.
> 
> example:
> 
> import javax.faces.context.FacesContext;
> import javax.faces.component.html.HtmlCommandLink;  
> ....
> HtmlCommandLink commandLink =
> (HtmlCommandLink)context.getApplication().createComponent(HtmlCommandLink.COMPONENT_TYPE);
> 
> koshi a écrit :
>> Hi, first of all, thanks for all your post and ideas, i'm grateful for your
>> support.
>>
>> i decided to solve my problem this way
>>
>> in the view: 
>>   <h:panelGrid binding="#{managedBean.panelGrid}" /> 
>>
>> the managed bean:
>> public HtmlPanelGrid getPanelGrid ()
>> {
>>       HtmlPanelGrid grid = new HtmlPanelGrid ();
>>       ....
>>
>>       for (Actions action : actions) {
>>       
>>             if (action.getType () == ActionTypes.COMMAND_LINK) {
>>                     HtmlCommandLink link = new HtmlCommandLink ();
>>                     link.setId (action.getId ());
>>                     link.setTitle (action.getTitle ());
>>  
>>                     HtmlOutputText text = new HtmlOutputText ();
>>                     text.setValue (MessagesUtil.getMessage ("actions",
>> action.getTitle (), null));
>>         
>>                     link.getChildren ().add (text);
>>         
>>                     MethodBinding method = FacesContext.getCurrentInstance
>> ().getApplication ().
>>                                     createMethodBinding (action.getValue (),
>> null);
>>                     link.setAction (method);
>>                     grid.getChildren ().add (link);
>>             }
>>       }
>>       return grid;
>> }
>>
>> but the commandLink doesn't work, and i have no idea of what is happening.
>>
>> if i put a commandLink into the panelGrid manually, then the commandLink
>> works fine.
>>
>> <h:panelGrid id="id" binding="#{managedBean.panelGrid}">
>>        <h:commandLink id = "asd"  action="#{managedBean.action}">
>>             <h:outputText value="action name" />
>>        </h:commandLink>
>> </h:panelGrid>
>>
>> Thanks
>>   
> 


Re: Newbie question: How to generate a jsf component dynamically

Posted by David Delbecq <de...@oma.be>.
Those calls (and other components you may create) are wrong:
       HtmlPanelGrid grid = new HtmlPanelGrid ();
       HtmlCommandLink link = new HtmlCommandLink ();

To create component, use the FacesContext.getApplication().createComponent(componentType) call.

example:

import javax.faces.context.FacesContext;
import javax.faces.component.html.HtmlCommandLink;  
....
HtmlCommandLink commandLink =
(HtmlCommandLink)context.getApplication().createComponent(HtmlCommandLink.COMPONENT_TYPE);

koshi a écrit :
> Hi, first of all, thanks for all your post and ideas, i'm grateful for your
> support.
>
> i decided to solve my problem this way
>
> in the view: 
>   <h:panelGrid binding="#{managedBean.panelGrid}" /> 
>
> the managed bean:
> public HtmlPanelGrid getPanelGrid ()
> {
>       HtmlPanelGrid grid = new HtmlPanelGrid ();
>       ....
>
>       for (Actions action : actions) {
>       
>             if (action.getType () == ActionTypes.COMMAND_LINK) {
>                     HtmlCommandLink link = new HtmlCommandLink ();
>                     link.setId (action.getId ());
>                     link.setTitle (action.getTitle ());
>  
>                     HtmlOutputText text = new HtmlOutputText ();
>                     text.setValue (MessagesUtil.getMessage ("actions",
> action.getTitle (), null));
>         
>                     link.getChildren ().add (text);
>         
>                     MethodBinding method = FacesContext.getCurrentInstance
> ().getApplication ().
>                                     createMethodBinding (action.getValue (),
> null);
>                     link.setAction (method);
>                     grid.getChildren ().add (link);
>             }
>       }
>       return grid;
> }
>
> but the commandLink doesn't work, and i have no idea of what is happening.
>
> if i put a commandLink into the panelGrid manually, then the commandLink
> works fine.
>
> <h:panelGrid id="id" binding="#{managedBean.panelGrid}">
>        <h:commandLink id = "asd"  action="#{managedBean.action}">
>             <h:outputText value="action name" />
>        </h:commandLink>
> </h:panelGrid>
>
> Thanks
>   


Re: Newbie question: How to generate a jsf component dynamically

Posted by koshi <ko...@ya.com>.
Hi, first of all, thanks for all your post and ideas, i'm grateful for your
support.

i decided to solve my problem this way

in the view: 
  <h:panelGrid binding="#{managedBean.panelGrid}" /> 

the managed bean:
public HtmlPanelGrid getPanelGrid ()
{
      HtmlPanelGrid grid = new HtmlPanelGrid ();
      ....

      for (Actions action : actions) {
      
            if (action.getType () == ActionTypes.COMMAND_LINK) {
                    HtmlCommandLink link = new HtmlCommandLink ();
                    link.setId (action.getId ());
                    link.setTitle (action.getTitle ());
 
                    HtmlOutputText text = new HtmlOutputText ();
                    text.setValue (MessagesUtil.getMessage ("actions",
action.getTitle (), null));
        
                    link.getChildren ().add (text);
        
                    MethodBinding method = FacesContext.getCurrentInstance
().getApplication ().
                                    createMethodBinding (action.getValue (),
null);
                    link.setAction (method);
                    grid.getChildren ().add (link);
            }
      }
      return grid;
}

but the commandLink doesn't work, and i have no idea of what is happening.

if i put a commandLink into the panelGrid manually, then the commandLink
works fine.

<h:panelGrid id="id" binding="#{managedBean.panelGrid}">
       <h:commandLink id = "asd"  action="#{managedBean.action}">
            <h:outputText value="action name" />
       </h:commandLink>
</h:panelGrid>

Thanks
-- 
View this message in context: http://www.nabble.com/Newbie-question%3A-How-to-generate-a-jsf-component-dynamically-tf2743954.html#a7677123
Sent from the MyFaces - Users mailing list archive at Nabble.com.