You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by David Delbecq <de...@oma.be> on 2006/07/13 15:27:55 UTC

Custom component with childrens

Hello all,

Starting to learn JSF, i tried to create my custom UI component. Because
it will be made of several fields and button, i decided to extends
HTMLPanelGrid. The constructor creates the various components part of
the Panel. After getting "funny" errors in console, i worked on a step
by step and noticed in restore view, myfaces does inject childs in my
component (so the number of child is double: those created at
intanciation of my component and those saved from previous instance and
injected as part of restore view).

My question is, considering the way i do it for now (which is bad ;) ),
what is the best way to avoid this restore view problem. How can my
component know if it is in a state where it need to create itself it's
children or in a state where the controller will restore the children
tree itself?

Thank for help.

public class HTMLAddressComponent extends HtmlPanelGrid implements
        NamingContainer {
.....

    public HTMLAddressComponent(){
        street = new HtmlInputText();
        number = new HtmlInputText();
        town = new HtmlInputText();
        postCode = new HtmlInputText();
        command = new HtmlCommandButton();
        command.setValue("enable/disable");
        street.setId("street");
        number.setId("number");
        town.setId("town");
        postCode.setId("postCode");
        command.setId("command");
        List childs = getChildren();
        HtmlPanelGroup group = new HtmlPanelGroup();
        List l = group.getChildren();
        l.add(getText("Street: "));
        l.add(street);
        l.add(getText("Number: "));
        l.add(number);
        childs.add(group);
        group = new HtmlPanelGroup();
        l = group.getChildren();
        l.add(getText("postcode: "));
        l.add(postCode);
        l.add(getText("Town: "));
        l.add(town);
        childs.add(group);
        childs.add(command);
    }
    private UIComponent getText(String value){
        HtmlOutputText text = new HtmlOutputText();
        text.setValue(value);
        return text;
    }



Re: Custom component with childrens

Posted by David Delbecq <de...@oma.be>.
Thank you all. I finally managed to find a quick and easy way to do it
without ressorting to facelets. I simply set the value bean in the
request map using a specific clientid specific name and i inject this
value during the processXXX calls. This work well with actions and with
properties.

Greetings,
David Delbecq

Mike Kienenberger wrote:
> On 7/14/06, Andrew Robinson <an...@gmail.com> wrote:
>> Facelets gives you great power for composite controls. It is much
>> easier to build them that way then to build them programatically.
>
> Yeah, I really don't think this can be emphasised too much.
> Doing this in JSF/facelets takes about 10 minutes.   Doing it in
> JSF/JSP is going to take days.
>
> That's why I can only tell you what I did a year ago: I don't do
> things like this anymore -- I have better uses for my time than trying
> to make composite components in standard JSF/JSP.


Re: Custom component with childrens

Posted by Mike Kienenberger <mk...@gmail.com>.
On 7/14/06, Andrew Robinson <an...@gmail.com> wrote:
> Facelets gives you great power for composite controls. It is much
> easier to build them that way then to build them programatically.

Yeah, I really don't think this can be emphasised too much.
Doing this in JSF/facelets takes about 10 minutes.   Doing it in
JSF/JSP is going to take days.

That's why I can only tell you what I did a year ago: I don't do
things like this anymore -- I have better uses for my time than trying
to make composite components in standard JSF/JSP.

Re: Custom component with childrens

Posted by Andrew Robinson <an...@gmail.com>.
FYI: You can pass method bindings in facelets, it just requires a
little bit of work.

I posted a blog on this:
http://andrewfacelets.blogspot.com/2006/06/creating-composite-controls-with-jsf.html

Facelets gives you great power for composite controls. It is much
easier to build them that way then to build them programatically.

-Andrew

On 7/14/06, Mike Kienenberger <mk...@gmail.com> wrote:
> > Mike Kienenberger a écrit :
> > > Composite components are a lot easier if you add facelets into the mix
> > > as it can all be done in templating code.
>
> On 7/13/06, delbd <de...@oma.be> wrote:
> > No, my composition will not be simple in the end  and i need to provide
> > a simple to use taglib. (with elements like '<mylib:myComponent
> > value=.... id=..../>'
>
> Well, facelets allows you to define a tag for your included template
> file it looks just like any other component.   But if you're
> developing a public library, you won't want to restrict it to
> facelets.
>
> > Thanks for you example, it seems you are going a similar way to mine
>
> Just keep in mind that it's a year old, and that I ended up dropping
> it shortly thereafter for a trivial facelets implementation, so while
> it's an example, it's probably not a perfect one.
>
> > If i might ask an additionnal question, my component will be a composite
> > component containing fields but also actions. I need somehow to be able
> > to know on which bean the action will be invoked. I thought about doing
> > it this way: action="#{theBean.theAction()}". The problem for my
> > composite component is that "theBean" is the result of value field of my
> > component tag. So i don't really know how my 'createChildrens()' method
> > is supposed to initialize  the action parameter of HtmlCommandButton. I
> > tried to set an intermediate bean in the request attributes and
> > reference it in action, but, while it works for input fields value, this
> > intermediate field is not available at action method evaluation time.
> > Have you experience with composite component containg actions?
>
> I would create your own custom MethodBinding class.  I think I created
> a custom class in my example as well.    Pass your action as a
> ValueBinding, but assign your custom class as the methodBinding for
> the button.   Then have your custom class compute a real method
> binding using the ValueBinding of the action name plus the value of
> the bean name.
>

Re: Custom component with childrens

Posted by Mike Kienenberger <mk...@gmail.com>.
> Mike Kienenberger a écrit :
> > Composite components are a lot easier if you add facelets into the mix
> > as it can all be done in templating code.

On 7/13/06, delbd <de...@oma.be> wrote:
> No, my composition will not be simple in the end  and i need to provide
> a simple to use taglib. (with elements like '<mylib:myComponent
> value=.... id=..../>'

Well, facelets allows you to define a tag for your included template
file it looks just like any other component.   But if you're
developing a public library, you won't want to restrict it to
facelets.

> Thanks for you example, it seems you are going a similar way to mine

Just keep in mind that it's a year old, and that I ended up dropping
it shortly thereafter for a trivial facelets implementation, so while
it's an example, it's probably not a perfect one.

> If i might ask an additionnal question, my component will be a composite
> component containing fields but also actions. I need somehow to be able
> to know on which bean the action will be invoked. I thought about doing
> it this way: action="#{theBean.theAction()}". The problem for my
> composite component is that "theBean" is the result of value field of my
> component tag. So i don't really know how my 'createChildrens()' method
> is supposed to initialize  the action parameter of HtmlCommandButton. I
> tried to set an intermediate bean in the request attributes and
> reference it in action, but, while it works for input fields value, this
> intermediate field is not available at action method evaluation time.
> Have you experience with composite component containg actions?

I would create your own custom MethodBinding class.  I think I created
a custom class in my example as well.    Pass your action as a
ValueBinding, but assign your custom class as the methodBinding for
the button.   Then have your custom class compute a real method
binding using the ValueBinding of the action name plus the value of
the bean name.

Re: Custom component with childrens

Posted by delbd <de...@oma.be>.
Mike Kienenberger a écrit :

> Composite components are hard to do in standard JSF.
>
> There's a year-old example where I did something like this at the
> following URL.  I remember having similar issues and fixing them.
>
> http://issues.apache.org/jira/secure/attachment/12311217/RowAndColumnRelationshipComponent.zip
>
>
> Composite components are a lot easier if you add facelets into the mix
> as it can all be done in templating code.
>
> You might also be able to use a jsp:include if your composition is
> simple enough.
>
No, my composition will not be simple in the end  and i need to provide
a simple to use taglib. (with elements like '<mylib:myComponent
value=.... id=..../>'
Thanks for you example, it seems you are going a similar way to mine,
thought your check to know if you need to generate childrens seems
cleaner than mine. I will study it further at work tomorrow ^^.

If i might ask an additionnal question, my component will be a composite
component containing fields but also actions. I need somehow to be able
to know on which bean the action will be invoked. I thought about doing
it this way: action="#{theBean.theAction()}". The problem for my
composite component is that "theBean" is the result of value field of my
component tag. So i don't really know how my 'createChildrens()' method
is supposed to initialize  the action parameter of HtmlCommandButton. I
tried to set an intermediate bean in the request attributes and
reference it in action, but, while it works for input fields value, this
intermediate field is not available at action method evaluation time.
Have you experience with composite component containg actions?

Thanks for your time,
Delbecq David

> On 7/13/06, David Delbecq <de...@oma.be> wrote:
>
>> Hello all,
>>
>> Starting to learn JSF, i tried to create my custom UI component. Because
>> it will be made of several fields and button, i decided to extends
>> HTMLPanelGrid. The constructor creates the various components part of
>> the Panel. After getting "funny" errors in console, i worked on a step
>> by step and noticed in restore view, myfaces does inject childs in my
>> component (so the number of child is double: those created at
>> intanciation of my component and those saved from previous instance and
>> injected as part of restore view).
>>
>> My question is, considering the way i do it for now (which is bad ;) ),
>> what is the best way to avoid this restore view problem. How can my
>> component know if it is in a state where it need to create itself it's
>> children or in a state where the controller will restore the children
>> tree itself?
>>
>> Thank for help.
>>
>> public class HTMLAddressComponent extends HtmlPanelGrid implements
>>         NamingContainer {
>> .....
>>
>>     public HTMLAddressComponent(){
>>         street = new HtmlInputText();
>>         number = new HtmlInputText();
>>         town = new HtmlInputText();
>>         postCode = new HtmlInputText();
>>         command = new HtmlCommandButton();
>>         command.setValue("enable/disable");
>>         street.setId("street");
>>         number.setId("number");
>>         town.setId("town");
>>         postCode.setId("postCode");
>>         command.setId("command");
>>         List childs = getChildren();
>>         HtmlPanelGroup group = new HtmlPanelGroup();
>>         List l = group.getChildren();
>>         l.add(getText("Street: "));
>>         l.add(street);
>>         l.add(getText("Number: "));
>>         l.add(number);
>>         childs.add(group);
>>         group = new HtmlPanelGroup();
>>         l = group.getChildren();
>>         l.add(getText("postcode: "));
>>         l.add(postCode);
>>         l.add(getText("Town: "));
>>         l.add(town);
>>         childs.add(group);
>>         childs.add(command);
>>     }
>>     private UIComponent getText(String value){
>>         HtmlOutputText text = new HtmlOutputText();
>>         text.setValue(value);
>>         return text;
>>     }
>>
>>
>>


Re: Custom component with childrens

Posted by Mike Kienenberger <mk...@gmail.com>.
Composite components are hard to do in standard JSF.

There's a year-old example where I did something like this at the
following URL.  I remember having similar issues and fixing them.

http://issues.apache.org/jira/secure/attachment/12311217/RowAndColumnRelationshipComponent.zip

Composite components are a lot easier if you add facelets into the mix
as it can all be done in templating code.

You might also be able to use a jsp:include if your composition is
simple enough.

On 7/13/06, David Delbecq <de...@oma.be> wrote:
> Hello all,
>
> Starting to learn JSF, i tried to create my custom UI component. Because
> it will be made of several fields and button, i decided to extends
> HTMLPanelGrid. The constructor creates the various components part of
> the Panel. After getting "funny" errors in console, i worked on a step
> by step and noticed in restore view, myfaces does inject childs in my
> component (so the number of child is double: those created at
> intanciation of my component and those saved from previous instance and
> injected as part of restore view).
>
> My question is, considering the way i do it for now (which is bad ;) ),
> what is the best way to avoid this restore view problem. How can my
> component know if it is in a state where it need to create itself it's
> children or in a state where the controller will restore the children
> tree itself?
>
> Thank for help.
>
> public class HTMLAddressComponent extends HtmlPanelGrid implements
>         NamingContainer {
> .....
>
>     public HTMLAddressComponent(){
>         street = new HtmlInputText();
>         number = new HtmlInputText();
>         town = new HtmlInputText();
>         postCode = new HtmlInputText();
>         command = new HtmlCommandButton();
>         command.setValue("enable/disable");
>         street.setId("street");
>         number.setId("number");
>         town.setId("town");
>         postCode.setId("postCode");
>         command.setId("command");
>         List childs = getChildren();
>         HtmlPanelGroup group = new HtmlPanelGroup();
>         List l = group.getChildren();
>         l.add(getText("Street: "));
>         l.add(street);
>         l.add(getText("Number: "));
>         l.add(number);
>         childs.add(group);
>         group = new HtmlPanelGroup();
>         l = group.getChildren();
>         l.add(getText("postcode: "));
>         l.add(postCode);
>         l.add(getText("Town: "));
>         l.add(town);
>         childs.add(group);
>         childs.add(command);
>     }
>     private UIComponent getText(String value){
>         HtmlOutputText text = new HtmlOutputText();
>         text.setValue(value);
>         return text;
>     }
>
>
>