We have a custom component library that basically just decorates the stock Faces components with Bootstrap classes (basically a successor to the now-dead BootFaces project).
What we're trying to do is have a theme of "the whole kitchen sink" with forms... so when you add an input component, it automatically includes a bit of padding around the object, a label, the actual input, then a message for the input.
One way to solve this would be to implement a bunch of composite components: https://stackoverflow.com/tags/composite-component/info but there are some cases where we need pretty tight control of whats being rendered, as bootstrap has some funny quirks.
So in the case of the input component, we want the developer to do something like:
<mf:inputText .../>
but really that gives them:
- inputTextParent
- padding component
- label component
- actual input field component
- message component
In the inputTextParent, is there a proper way to modify the component tree and add sub-components? More importantly If someone does this:
<mf:inputText ...>
<h:somethingElse ../>
</mf:inputText>
Is there a way to delegate <h:somethingElse ../>
to a child component?
- inputTextParent
- padding component
- label component
- actual input field component
- h:somethingElse
- message component
Right now, we're doing roughly doing this in the contructor of the component... which will not properly delegate h:somethingElse
to be a subchild of actual input field component
. And I'm sure this is not a legal time to manipulate the component tree!
public MFInputTextComponentParent() {
setRendererType(getComponentName());
final FacesContext context = FacesContext.getCurrentInstance();
final Application application = context.getApplication();
final MFPadComponent pad = (MFPadComponent) application.createComponent(MFPadComponent.COMPONENT);
pad.setPadType("y");
pad.setPad(1);
super.getChildren().add(pad);
final MFInternalLabelComponent label = (MFInternalLabelComponent) application
.createComponent(MFInternalLabelComponent.COMPONENT);
pad.getChildren().add(label);
final MFInternalInputTextComponentParent inputText = createInternalInputText(application);
pad.getChildren().add(inputText);
final MFInternalMessageComponent message = (MFInternalMessageComponent) application
.createComponent(MFInternalMessageComponent.COMPONENT);
pad.getChildren().add(message);
}
The trick here is to use PostAddToViewEvent
to further populate the JSF view root tree with additional child components. Crucial here is to give each component you add a unique ID. See also section 2.12 Dynamic Components of:
https://github.com/e-Contract/enterprise-jsf/releases/download/enterprise-jsf-1.3.0/enterprise-jsf.pdf