Validator for input field inside composite component is never fired
Asked Answered
V

1

8

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.

Verla answered 30/8, 2012 at 1:18 Comment(1)
take a look at this tutorial ibm.com/developerworks/java/library/j-jsf2fu0111/… it seems to have exactly what your looking for...Pluperfect
C
9

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>

See also:


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" ... />
Crucifer answered 30/8, 2012 at 3:33 Comment(2)
I actually had the 'for' attribute in my validator. Merely a transcription error. I have corrected my question to reflect it. Additionally, I have made use of <h:outputLabel />. I just didn't have the reference code with me at the time to copy-paste it in. For what it's worth, adding 'for' doesn't help me in this exact situation. If I remove the outer facelet (<xxx:input />) and only have the facelet for the input field itself, it works just fine. That's why I am assuming it's the facelet-in-a-facelet thing causing the problem.Verla
See updated answer. You need to specify <composite:editableValueHolder> in the input.xhtml composite as well.Crucifer

© 2022 - 2024 — McMap. All rights reserved.