Mr.J4mes
Mr.J4mes

Reputation: 9266

How to clear an input field in the Validator class?

In my application, I have the following Validator to validate a captcha input:

@Named(value = "simpleCaptchaValidator")
@RequestScoped
public class SimpleCaptchaValidator implements Validator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        HttpSession session       = (HttpSession) context.getExternalContext().getSession(false);
        Captcha     secretCaptcha = (Captcha) session.getAttribute(Captcha.NAME);

        // Clear the input field
        EditableValueHolder input = (EditableValueHolder) component;
        input.resetValue();

        // Display an error msg if the entered words are wrong
        if (!secretCaptcha.isCorrect(value.toString())) {
            FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Failed!", "You have entered wrong words.");
            throw new ValidatorException(msg);
        }
    }
}

The above Validator works great on non-Ajax requests when users do enter wrong captcha words. However, if users enter the right captcha words but there's a validation failed on other components, the input field for the captcha is not cleared.

I'd be very grateful if you could show me how to solve the above problem.

Upvotes: 2

Views: 610

Answers (1)

BalusC
BalusC

Reputation: 1108632

It doesn't work because the EditableValueHolder#resetValue() is invoked at the wrong moment. You should be invoking it during invoke application phase (at least, after update model values phase), not in middle of validations phase. Namely, when the validate() method returns without exception, then JSF will still set the validated value as component's local value. When the validations phase has failed in general, then the update model values phase won't be invoked and the local value still sticks around in the component.

Based on the information provided so far, it isn't possible to propose the right approach. If this is a custom component, then just don't write the value during encode(). Or, if this is an existing component, then perhaps your best bet is to create a custom converter which stores the submitted value as a custom component attribute and then returns null in getAsObject(). In the validator, you then just grab that custom component attribute as value. As last resort, attach a PhaseListener which resets the component at the right moment.

Upvotes: 2

Related Questions