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).
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:
publicclass 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:
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.).
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 ?
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 ?
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).
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.
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.
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 ?
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.
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
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...
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?
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.
publicclass 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);
returnnew Object[] {superState, new Integer(getChildCount())};
}
publicvoid 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 »