How to evaluate a FacesComponent property inside a custom component

492 Views Asked by At

Lately, I've been working on a dynamic form project but is stop with a custom component problem. What I have:

A faces component for formField:

@FacesComponent(value = "formField")
public class FormFieldCompositeComponent { 
    private boolean email;
}

A custom component jsf:

<o:validator for="email_text" validatorId="emailValidator" disabled="#{not cc.email}" />

OR

<c:if test="#{not cc.email}">
    <f:validator for="email_text" validatorId="emailValidator"></f:validator>
</c:if>

OR

<f:validator disabled="#{not cc.email}" for="email_text" validatorId="emailValidator"></f:validator>

And the validator:

@FacesValidator("emailValidator")
public class EmailValidator implements Validator { }

My problems are:

1.) If I use an ordinary f:validator, like the one I use above and then use c:if to enable/disable it, then it will not work. According to some articles I've read it's because f:validator validates on build time, not on render time.

2.) If I use o:validator, it works but the problem is every time you hit submit a new line of invalid email error is added to p:messages. Example I clicked submit button 3 times, then I get 3 times the email error.

Any idea?

More info (anatomy of the project) Example I have a page user with field email, it will include the following custom components:

+user.xhtml
 +formPanel
 +formField (this is where the validator is defined)
  +formButtons (the action button)
  +p:messages is defined

user.xhtml

<formPanel>
  <formField field="email" />
  <formButtons />
</formPanel>

Command button is like (formButtons):

<p:commandButton id="saveButton" rendered="#{cc.attrs.edit}"
    value="#{messages['action.save']}"
    action="#{cc.attrs.backingBean.saveOrUpdate()}" icon="ui-icon-check"
    ajax="#{cc.attrs.ajaxSubmit}">
    <c:if test="#{cc.attrs.backingBean.lcid != null}">
        <f:param name="cid" value="#{cc.attrs.backingBean.lcid}" />
    </c:if>
</p:commandButton>

The p:messages as defined on formPanel:

<p:messages id="formMessages" showDetail="true" showSummary="false" redisplay="false"></p:messages>

Note:
1.) What I've noticed is that the validator is called n times, where n is the number of submit or click done.

xhtml - https://github.com/czetsuya/crud-faces/blob/master/crud-faces/src/main/webapp/administration/user/user.xhtml

the tags - https://github.com/czetsuya/crud-faces/tree/master/crud-faces/src/main/webapp/resources/tags

bean component - https://github.com/czetsuya/crud-faces/tree/master/crud-faces/src/main/java/org/manaty/view/composite

1

There are 1 best solutions below

0
On BEST ANSWER

Seems like there's no chance for the f:validator so I push through o:validator and come up with a workaround. Need to catch if the error is already in the FacesMessages list:

boolean match = false;
for (FacesMessage fm : context.getMessageList()) {
    if (fm.getDetail().equals(message)
            || fm.getSummary().equals(message)) {
        match = true;
        break;
    }
}

if (!match) {
    throw new ValidatorException(facesMessage);
}