participate


JavaServer Faces - Building Custom Component consisting of standard JSF Components
<<   Back to Forum  |   Give us Feedback
7 Duke Stars available
This topic has 19 replies on 2 pages.    1 | 2 | Next »
JSFUser
Posts:6
Registered: 11/10/06
Building Custom Component consisting of standard JSF Components   
Nov 10, 2006 1:44 AM

 
Hi there,

I have searched the web quite some time, the forums as well but cannot find an answer to my question.
I want to create a custom component consisting of 2 Input fields ("InputA" and "InputB")
(this is just for sake of simplicity, the actual component would be more complex).
I want to include the component explicitly just with one tag, and have the component render its children by itself.

    <foo:customComp  ... />


Now there are tons of examples, that create a custom component having two e.g. String properties holding the value for InputA and InputB and then a custom renderer which will render input fields by hand (the HTML to be created).

public class CustomComp extends ComponentBase {
   private String inputA;
   private String inputB;
  ...
}


I think this fails short of what JSF really tries to accomplish.
If you create a custom component that will include components for which there are already finished Standard Components, then by all means they use them !

Therefore I would think the Custom Component Class has UIInput Components, that get added as children to the Custom Component:

public class CustomComp extends ComponentBase {
  private UIInput inputA;
  private UIInput inputB;
 
  public CustmComp() {
    this.inputA = new UIInput();
    this.inputB = new UIInput();
 
   // initialize components some more e.g. ID
 
   //add components to the custom component
   this.getChildren().add(this.inputA);
   this.getChildren().add(this.inputB);
  }
  ...
 
 
}


Now I can get my example to render the child components, but of course the example only starts to make sense, if the two input fields can have a value binding attached.
I would like to have the input's HTML value field to have a value binding with a backing bean. This should not be something that should not be configurable when including the tag in the jsp. (Making it configurable could be another step but I need to get it to work first).

As far as I understand JSF, in order to create a ValueBinding, it needs to be bound when creating teh UIInput fields, thus the above code would then include in its constructor

    this.inputA = new UIInput();
 
    ExpressionFactory factory = ctx.getApplication().getExpressionFactory();
 
    ValueExpression ve = factory.createValueExpression(ctx.getELContext(),
                "#{myBackingBean.fieldA}", String.class);
         
    this.inputAsetValueExpression("value", ve);    
 
 
    this.getChildren().add(this.inputA);


I think that the custom component is ok so far. I cannot get my exampel to work and I think it might be a problem in the Renderer.

I have a Custom renderer that includes in its encodeBegin phase:

    UIInput inputA= customComponent.getInputA();
    inputA.encodeBegin(context);
    inputA.encodeChildren(context);
    inputA.encodeEnd(context);


I am not sure if this is the correct way to do it and how the decode method would look like.

Any help would be appreciated. I think this to be a major issue for building custom components to build them out of Standard JSF components whenever possible and let these tested and working standard components do all work (e.g. rendering themselves etc.).

Any help would be appreciated !

Thanks in advance,

Lars
 
FabioLin
Posts:1
Registered: 11/10/06
Re: Building Custom Component consisting of standard JSF Components      
Nov 10, 2006 8:01 AM (reply 1 of 19)  (In reply to original post )

 
Take a look at facelets. I don't know exactly why you want to build a component like that, but I belive I reached a similar behavior using sourceTags.
 
JSFUser
Posts:6
Registered: 11/10/06
Re: Building Custom Component consisting of standard JSF Components   
Nov 13, 2006 1:27 AM (reply 2 of 19)  (In reply to #1 )

 
Thanks for your response.

Well yes, facelets would let me do this, but I would like to achieve the functionality with plain JSF.

I just do not understand why there are millions of examples building composite custom components but then do the rendering of the components ("servlet-style writer.write(<input ...)") themselves.
Why not use a UIInput component inside instead and let that component do the rendering.

All those composite custom component examples doing the rendering of standard components themselves in my opinion fall short of what the real benefit is from reusing components.

Am I the only one who thinks that composite custom components should consist of standard JSF components whenever possible ?
 
Tomarenz
Posts:57
Registered: 3/16/06
Re: Building Custom Component consisting of standard JSF Components      
Nov 18, 2006 6:06 AM (reply 3 of 19)  (In reply to #2 )

 
I fully agree, but Facelets make the job much easier. You just define components by bracketing plain jsf chunks inside <ui:composition> pairs. Then you include such components inside any page you like. This way beans and bindings are fully defined. Only a simple xml tag lib is needed to publish the component. This is all I use from Facelets (I'm not interested in templating).
However: I was not able to discover how to use such components from Java (e.g. from custom components). I guess it should go through createComponent somehow. Does anybody know that ?
 
JSFUser
Posts:6
Registered: 11/10/06
Re: Building Custom Component consisting of standard JSF Components   
Nov 20, 2006 7:57 AM (reply 4 of 19)  (In reply to #3 )

 
Thanks Tomarenz. I know I can achive similar functionality using facelets, but there should be a way to build a component dynamically as well.

If I have a custom Tag and want to create a component (which then creates child components), where would I put the creation ?

- createComponent method in the Tag class ?
(works until I want to add children.
newComponent.getChildren() returns null (!!) so I guess the custom component is not fully initialized in createComponent()).

- in the constructor of the custom component ?
If yes, then how does this work with restoring the childComponent in the restoreState() method of my custom component ? I get a child component from my constructor and a child component from my restoreView. not good)

- somewhere else ?


Any help would be appreciated. all examples found so far fall short of building composite custom components which are fully integrated in the JSF lifecycle (converting, validation, postback come to mind).

Any help is appreciated :)

Lars
 
Tomarenz
Posts:57
Registered: 3/16/06
Re: Building Custom Component consisting of standard JSF Components   
Nov 21, 2006 1:27 AM (reply 5 of 19)  (In reply to #4 )

 
I'm very interested as well.
However I'm still convinced that describing a layout by a jsp/xhtml page is much easier than creating it from scratch in java (where you have to play a lot with attributes to achieve the same net result), but nevertheless it seems we have no solution to either ways.
I'm playing since several months with jsf/facelets/Tomahawk, and composition is by far the weakest point in this game. Even in case of facelets, I discovered that ui:components are just included chuncks of xhtml contents, e.g. they are no components at all. They have no identity and thus no runtime creation is possible. Hence no reuse from java.
 
JoaoBosco
Posts:8
Registered: 11/21/06
Re: Building Custom Component consisting of standard JSF Components   
Nov 21, 2006 5:42 AM (reply 6 of 19)  (In reply to #4 )

 
JSFUser,

I have lots of problems trying to develop a componet made of standard JSF Componets. As you said, why should we decode or encode the standard components by hand ? All examples said to do that but nobody explains why it is necessary. I?m really angry with it.

Consider you are subclassing UInput. For some reason you can?t use the inherited methods due to nullPointerException or other strange behavior.

I?ve tried to create standard components during encoding. During redering my component I call standardComponent.encode(). During decode I do the same. Remember that you need to implement saveState and restoreState.

Other strange thing is that you need to create value bindings for the UIInput but you are subclassing it, It shouldn?t be necessary.

I didn?t attach children to my component. The only thing I did was inputA.setParent() to set the correct id.

It almost works fine. Now I have problems trying to attach a render in the UIInput.

I think we are stucked in things that many articles said that is easy to do but they don?t demonstrate it clearly.

I know that my post isn?t helpful =) But I need to say: JSF sucks in many ways.
 
JoaoBosco
Posts:8
Registered: 11/21/06
Re: Building Custom Component consisting of standard JSF Components      
Nov 21, 2006 5:45 AM (reply 7 of 19)  (In reply to #6 )

 
Sorry man,

I forgot to send an interesting article:
http://www-128.ibm.com/developerworks/java/library/j-jsf4/

The article explains how to develop a custom component with two inputs. With a render and a validator.
 
JSFUser
Posts:6
Registered: 11/10/06
Re: Building Custom Component consisting of standard JSF Components   
Nov 21, 2006 6:42 AM (reply 8 of 19)  (In reply to #7 )

 
Thanks Joao,

I know the article but again, it falls short of what I would consider the real benefit from building custom components consisting of multiple standard components. In the article Richard Hightower creates a custom component which eventually represents just a single input field. He composes many input fields via writing them on tag after the other on the jsp.

What I am looking for is a composite custom component. That is a custom component acting as a container for two or more standard JSF Components (preferably two UIInput components as they are much harder to integrate than Output components :)).

Anyone able to present an example of a composite custom component consisting of two UIInput fields and all this is created / initialized programatically and not with facelets or using multiple tags to add the UIInput children ?.

I just know that the final solution to build such a composite component programatically will be few code and will look very elegant. Anybody able to bring some light into this ?

Lars
 
IamCowKing
Posts:731
Registered: 11/25/05
Re: Building Custom Component consisting of standard JSF Components   
Nov 21, 2006 9:21 AM (reply 9 of 19)  (In reply to #8 )

 
Lars, I think you're close.

In full disclosure, I have never done this before myself... Or read an article on how to do it. But the topic peeked my interest and I think that JSF is capable. On the other hand, I don't have a ton of time on my hands right now, or else I would sit down and actually write a composite component. It might still come to that.

In the meantime, I have some suggestions for you to try. You seem to understand custom components well enough that you probably won't need exhaustive examples (this is what I don't have time to do right now).

Essentially, what you have is one tag. So you'll have to create a tag entry in a TLD and a tag class. Next, you'll need a component class. This component class will essentially be a container for the other JSF standard components in your composite. So you'll need a getter and setter for HTMLInputText, HTMLCommandButton, etc... (whatever components are in your composite).

The tag class will create the each standard component in the setProperties method. Then set those components in the custom container component.

Lastly, you'll need a custom renderer. There are four key methods in the renderer: encodeBegin, encodeChildren, encodeEnd, and decode. Each of these methods has a param passed in that contains your UIComponent (ie. your custom composite component). Technically, all you should use is encodeBegin and decode for the composite component.

Use the UIComponent to get each contained standard component. On each standard component from your renderers encodeBegin method:
a) Call getRenderer(). If it is null, skip to step c.
b) Use the renderer to call encodeBegin, encodeChildren and encodeEnd. Pass the component in as the UIComponent argument.
c) Call the standard components encodeBegin, encodeChildren and encodeEnd methods. If you performed step b, you probably don't need to do this step (I'm not sure though, try it out).

Finally, your renderers decode method should follow a similar pattern as the above steps. Same idea, get the renderer of the standard component and call the appropriate decode method (if available).

To me, this looks like it would work and it's exactly what I would try first.

Let me know how it goes, or if you have any questions.


CowKing
 
Tomarenz
Posts:57
Registered: 3/16/06
Re: Building Custom Component consisting of standard JSF Components   
Nov 21, 2006 10:53 AM (reply 10 of 19)  (In reply to #8 )

 
Lars, the book Core JSF has a chapter 9 entitled "Custom Components" with subchapter "Using child components and facets". Example is a tabbed pane.
All example sources can be retrieved from http://corejsf.com as a single zip file.
Enjoy -- Renzo
 
tb01923
Posts:1
Registered: 11/22/06
Re: Building Custom Component consisting of standard JSF Components   
Nov 22, 2006 12:16 PM (reply 11 of 19)  (In reply to #3 )

 
as far as I can tell you cannot programmatically instantiate a Facelet from a backing Bean. The faceletContext object (which ahas the ability to returna facelet object) ceases to exist outside of the TagHandler (i don' know the phase).

BUT facelets does make the Tag generation a touch easier by not having to code the Tag classes AND the TLD -- as their framework provides the basic implmentations for free...
 
RAPHEAD
Posts:16
Registered: 2/19/04
Re: Building Custom Component consisting of standard JSF Components   
Jan 15, 2007 4:31 AM (reply 12 of 19)  (In reply to #9 )

 
@CowKing

Do you really think it is necessary to render the child components manually.
I realized it as follows:

I added
    public boolean getRendersChildren( ) {
	return true;
    }

to my component and the childs get rendered as far as I see.

thx
 
IamCowKing
Posts:731
Registered: 11/25/05
Re: Building Custom Component consisting of standard JSF Components   
Jan 15, 2007 10:56 AM (reply 13 of 19)  (In reply to #12 )

 
@RAPHEAD

I was talking about a composite component, not child components. Lars was trying to create one tag/component that represented several of the JSF standard components.

i.e:
<%-- Note, there are no children --%>
<d:myComposite att1="blah" att2="blahblah" />


My understanding of getRendersChildren returning true, is that you are telling JSF to call the child component(s) renderer for you. Which is definitely better than attempting to render the children manually (and what you are saying).

You might be onto something. Perhaps, if you set each composite component as a child to your custom component, you may be able to make JSF do the rendering for you. Now that is definitely worth a try! Is that what you do?


CowKing
 
leo.mekenkamp
Posts:1
Registered: 1/16/07
Re: Building Custom Component consisting of standard JSF Components   
Jan 16, 2007 4:47 AM (reply 14 of 19)  (In reply to original post )

 
Hope you are still monitoring this thread, JSFUser. I have been struggling with the same problem, and found the following 'hack'. Since the code is simple enough, I will not go into the details. Hope this helps.

public class CompositeJsfComponent {
 
    public CompositeJsfComponent() {
        // MyInput extends UIComponent
        getChildren().add(new MyInput());
        getChildren().add(new MyInput());
        getChildren().add(new MyInput());
    }
 
    public Object processSaveState(FacesContext context) {
        Object superState = super.processSaveState(context);
        return new Object[] {superState, new Integer(getChildCount())};
    }
    
    public void processRestoreState(FacesContext context, Object state) {
        // At this point in time the tree has already been restored, but not before our ctor added the default children.
        // Since we saved the number of children in processSaveState, we know how many children should remain within
        // this component. We assume that the saved tree will have been restored 'behind' the children we put into it
        // from within the ctor.
        Object[] values = (Object[]) state;
        Integer savedChildCount = (Integer) values[1];
        for (int i = getChildCount() - savedChildCount.intValue(); i > 0; i--) {
            getChildren().remove(0);
        }
        super.processRestoreState(context, values[0]);
    }
 
}
 
This topic has 19 replies on 2 pages.    1 | 2 | Next »
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics
    Users Online : 25
  • Guests : 136

About Sun forums
  • Sun Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

    Check out our guide on Getting started with Sun Forums for a full walkthrough of how to best leverage the benefits of this community.

Powered by Jive Forums