Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validator for input field inside composite component is never fired

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.

like image 610
Shadowman Avatar asked Aug 30 '12 01:08

Shadowman


1 Answers

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:

  • How to specify a validator for an input component inside a composite component?

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" ... />
like image 61
BalusC Avatar answered Sep 19 '22 14:09

BalusC