Validation

Hi there,

i have a form with TextFields and Selects.

In the buttonClick() Event Method, I would like to validate the entries. How do i do that ?

Example: Checking the correct Mail-Format or minimum String Length.

Can I add regular Expressions to the Fields ?

Thank you!

Best regards
Thomas

I assume you used the Form class to create your form.

In this case validating things such as e-mail addresses and such is quite straight forward. Validator objects can be attached to all fields by calling the addValidator() method.

Here is an example for an e-mail validator class (I give no guarantees that the regular expression works) :wink:


private class EmailValidator implements Validator {
	/**
	 * Tests if the given value is valid
	 * @param value the value to test
	 */
	public boolean isValid(Object value) {
		try {
			validate(value)
		} catch (Validator.InvalidValueException ive) {
			return false;
		}
		return true;
	}
	
	/**
	 * Validates
	 * @param value the value to test
	 */
	public void validate(Object value) throws Validator.InvalidValueException {
		// Here value is a String containing what *should* be an e-mail address
		if (value instanceof String) {
			String email = (String)value;
			// Match the email string against a (simplistic) regular expression matching e-mail addresses
			if (!email.matches("^[_\w\.\-]
+@[\w\.-]
+\.[a-z]
{2,6}$"))
				throw new Validator.InvalidValueException("The e-mail address provided is not valid!");
		}
	}
}

The validator is used as follows:


TextField emailField = TextField("e-mail");
emailField.addValidator(new EmailValidator());

The validator is executed when you call form.validate().

If the field contains an error, an exclamation mark appears next to it and hovering the cursor on the exclamation mark gives you the reason why it failed. In this example the message is “The e-mail address provided is not valid!”

Hope this helps and don’t hesitate to ask if something is unclear!
/Jonatan

Hey Jonatan,

thank you so much for your fast and detailed answer! Helped me really out.
That’s easier than i’ve expected.

But I’m getting the red exclamation mark on the Save-Button with a really big exception message (not just the one sentence from the valid-class). Do you have an advice?

I have a Tabsheet with several Panels (each for every single Tab), which are extra classes extended from Panel.

The TextField and Form are initialized in one of the extra Panelclass constructer, the form.validate() in the buttonClick() event-method. Both objects, the TextField and the Form, are attributes of the class.

Thanks in advance,
Best regards
Thomas

The exclamation marks also appears in a button if an exception is thrown somewhere in the button’s click listener, or in code called from the click listener. I really recommend that you install
firebug
, through which you can view the exception much easier.

There isn’t much more I can say without knowing what kind of exception is thrown or seeing the source code, but using firebug you can easily view the entire text of the exception and examine the code from there. Just like in any other java application!

Oh, and in case you didn’t know yet: Appending “?debug” to the URL enables the debug mode of the Toolkit, which then prints more information to the firebug console. This usually helps when debugging applications.

HTH,
/Jonatan

Hi,

sorry, i didn’t mention that the exception is from the EmailValidator Class.
Looks like this:

Yes, the form.validate() Method is called in the buttonClick listener Method… but where else? I would like to check all the form values when the user hits the button. Then the exclamation marks appears in the button, and not next to the TextField.

Sorry if that’s trivial, I’m just getting started with IT Mill :oops:

And thanks for your advice with firebug and the ?debug parameter!

Best Regards,
Thomas

Yeah, validate() throws, so if you’ll want to handle that in your buttonclick handler somehow.

I’ve done something like this in a similar situation:

		Collection ids = form.getItemPropertyIds();
		for (Iterator it = ids.iterator();it.hasNext();) {
			Field field = (Field)form.getField(it.next());
			try {
				field.validate();
			} catch (InvalidValueException e) {
				if (field instanceof AbstractComponent) {
					((AbstractComponent)field).setComponentError(new UserError(e.getMessage()));
				}
			}
		}

The code in the catch-block attaches the error message to each field - in some cases you’ll want to collect all of the errors as well, and put them neatly in a Label just over the button, for instance.

Personally I think the Form should do this when you call validate(), or perhaps provide a function that returns Field+Exception -pairs for each invalid Field, so that you could decide what to do.
Anyway, this seems to work.

(ps. remember to remove error messages from valid fields, that’s missing above - oops)

yov

Oh, forgot: if you just want to mark the invalid fields, you could say field.setInvalidAllowed(false); and not call validate().

Yes, sorry about that. You need to catch the exception yourself and display the message in some way. Displaying it in a label as yov suggested is a good way.

/Jonatan

Any suggestions how this should be done?

I don’t actually use Validators in Form, but I wrap the errors given by service layer to the Form Fields. The wrapper always returns false to isValid, and throws the right error message in validate’s exception. But once I correct some fields and add these validators to currently invalid Fields, the old validators still show an error.

I noticed that there is a removeValidator method in Validatable, but it seems a bit impossible to remove a validator that doesn’t exist anymore ('cause the error has already been corrected).


public class ValidatorAdapter implements com.itmill.toolkit.data.Validator {
    private String errMsg
    public ValidatorAdapter(String errMsg) {
        this.errMsg=errMsg;
    }

    public void validate(Object value) throws InvalidValueException {
        throw new InvalidValueException(errMsg);
    }

    public boolean isValid(Object value) {
        return false;
    }
}

Field field = form.getField(propertyId);
field.addValidator(new ValidatorAdapter(errMsg));

Follow-up from myself…

A decent workaround is to use AbstractComponent.setComponentError instead on addValidator, but it has two downsides:

  1. can I always be sure, that a form field derives from AbstractComponent? Basically yes, if I always use my own FieldFactories, I guess.

  2. Only one error can exist per field at a time. But there a cases when there could be several errors per field (for example “input was too long” and “@ is an invalid character”).

So the validator approach would be more flexible…

Any suggestions?

For this issue you could use the CompositeErrorMessage implementation of the ErrorMessage interface.
http://toolkit.itmill.com/demo/doc/api/com/itmill/toolkit/terminal/CompositeErrorMessage.html

You can be certain that a field derives from the Component interface, as the first extends the latter. An AbstractComponent in turn implements the component interface.

Not quite. Both Field and AbstractComponent do implement Component interface, but the setComponentError is not defined in Component interface, only in AbstractComponent.

Yeah, not a bad idea at all. But this still has the same problem that I had with validators: no easy way to clear all errors from a form (since I have to get a field for each property one at a time, no collection available in Form). Otherwise this seems very nice. And of course I can loop through every property in the form because they aren’t dynamic, but it’d still be nicer if the form would give an iterator to its fields :slight_smile:

I am writing to you in hope that this time someone there have mercy and answer me why for instance email validator already implemented and running for sometime now is giving me complilation error of incompatibiliity type and then can not convert to Validator.
Please try to figure what happen. I am using 7.6.7 with netbeans 8.1

The validator implemented is the one introduced above by Jonatan Kronqvist. Would it be that the solution was so old that now is not any longer valid.

Please try to explain