I've created some Facelets to make developing our pages easier. Particularly, I've created a series of Facelets for input components. I have 1 Facelet, <xxx:input />
that displays a label around the input field. Beyond that, I have Facelets like <xxx:inputText />
and <xxx:inputSecret />
that render the actual input field. Each of these makes use of <xxx:input />
to display the label. The Facelet looks something like this:
<html ...>
<composite:interface>
...
</composite:interface>
<composite:implementation>
<label><h:outputText value="#{cc.attrs.labelText}" /></label>
<composite:insertChildren />
</composite:implementation>
</html>
The <xxx:inputText />
Facelet would then look like this...
<html ...>
<composite:interface>
...
</composite:interface>
<composite:implementation>
<xxx:input labelText=...>
<h:inputText id="myinput" ... />
</xxx:input>
</composite:implementation>
</html>
Everything renders just fine, but I am having troubles when trying to add <f:validator />
or other validation tags. From what I've read, I have to add a tag to my Facelet. So, I added <composite:editableValueHolder name="myinput" targets="myinput" />
line in the interface section. However, I still do not see my validator being fired. I have something like this in my .xhtml file...
...
<xxx:inputText value="...">
<f:validateLength minimum="10" for="myinput" />
</xxx:inputText>
...
Regardless of the input I enter, the validator never seems to fire and I never get an error message. A coworker suggested that it is due to the target ID I am using and the fact that it is wrapped by the <xxx:input />
Facelet.
Do I need to incorporate the parent component ID in my target definition? Is there something else that I'm missing? It works just fine if I exclude the <xxx:input />
Facelet, so I'm assuming it's something related to that, but don't know how to solve it. Any help you can provide is GREATLY appreciated.
You need to specify the for
attribute of the validator to match the name
of the <composite:editableValueHolder>
.
<xxx:inputText value="...">
<f:validateLength for="myinput" minimum="10" />
</xxx:inputText>
You also need to make sure that the <composite:editableValueHolder>
is specified in both composites, thus also the input.xhtml
one. Here's a complete example which works just fine for me on Mojarra 2.1.12:
/resources/components/input.xhtml
:
<ui:component
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:cc="http://java.sun.com/jsf/composite"
>
<cc:interface>
<cc:attribute name="label" required="true" />
<cc:editableValueHolder name="input" targets="input" />
</cc:interface>
<cc:implementation>
<h:outputLabel for="input" value="#{cc.attrs.label}" />
<cc:insertChildren />
</cc:implementation>
</ui:component>
/resources/components/inputText.xhtml
:
<ui:component
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:my="http://java.sun.com/jsf/composite/components"
>
<cc:interface>
<cc:attribute name="label" required="true" />
<cc:attribute name="value" required="true" />
<cc:editableValueHolder name="input" targets="input:text" />
</cc:interface>
<cc:implementation>
<my:input id="input" label="#{cc.attrs.label}">
<h:inputText id="text" value="#{cc.attrs.value}" />
</my:input>
</cc:implementation>
</ui:component>
Usage in some test.xhtml
:
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:my="http://java.sun.com/jsf/composite/components"
>
<h:head>
<title>SO question 12188638</title>
</h:head>
<h:body>
<h:form>
<my:inputText label="foo" value="#{bean.input}">
<f:validateLength minimum="10" for="input" />
</my:inputText>
<h:commandButton value="submit" action="#{bean.submit}">
<f:ajax execute="@form" render="@form"/>
</h:commandButton>
<h:messages/>
</h:form>
</h:body>
</html>
Unrelated to the concrete problem, are you aware of the <h:outputLabel>
?
<h:outputLabel value="#{cc.attrs.labelText}" />
And the fact that you can just inline EL in template text without explicit need for <h:outputText>
?
<label>#{cc.attrs.labelText}</label>
Have you noticed that your label is also missing the for
attribute which should reference the ID of the input element which the label should be referring to?
<h:outputLabel for="someId" ... />
<h:inputText id="someId" ... />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With