How to use the GWT editor framework for validation?
Asked Answered
G

5

19

I am trying to integrate with the new GWT Editor framework of GWT 2.1.0. I also want to add my validation checks into the framework. However, I am struggling to find a decent example how to do this.

For the moment I have the following code:

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:e="urn:import:com.google.gwt.editor.ui.client">
    <ui:with type="be.credoc.iov.webapp.client.MessageConstants"
        field="msg" />
    <g:HTMLPanel>
        <e:ValueBoxEditorDecorator ui:field="personalReference">
            <e:valuebox>
                <g:TextBox />
            </e:valuebox>
        </e:ValueBoxEditorDecorator>
    </g:HTMLPanel>
</ui:UiBinder> 

And for my editor:

public class GarageEditor extends Composite implements Editor<Garage> {

    @UiField
    ValueBoxEditorDecorator<String> personalReference;

    interface GarageEditorUiBinder extends UiBinder<Widget, GarageEditor> {
    }

    private static GarageEditorUiBinder uiBinder = GWT.create(GarageEditorUiBinder.class);

    public GarageEditor() {
        initWidget(uiBinder.createAndBindUi(this));
    }

}

On what point do I have to call my validator and how do I integrate with it?

Update:

I am actually looking for a way to retrieve a map with as key the property path, and as value the editor. There is a path field on a delegate, but this is not the path within the edited object, but the path in the editor class.

Does anybody know if it is possible to do something like this?

Gecko answered 4/11, 2010 at 15:59 Comment(0)
D
8

Annotate you beans with contstrants (see Person.java)

public class Person {
  @Size(min = 4)
  private String name;
}

Use the standard validation bootstrap to get a Validator on the client and validate your object (see ValidationView.java)

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Person>> violations = validator.validate(person);

Follow this pattern to create a Validator for the objects you want to validate on the client. (see SampleValidatorFactory.java)

public final class SampleValidatorFactory extends AbstractGwtValidatorFactory {

  /**
   * Validator marker for the Validation Sample project. Only the classes listed
   * in the {@link GwtValidation} annotation can be validated.
   */
  @GwtValidation(value = Person.class,
      groups = {Default.class, ClientGroup.class})
  public interface GwtValidator extends Validator {
  }

  @Override
  public AbstractGwtValidator createValidator() {
    return GWT.create(GwtValidator.class);
  }
}

Include the module for your Validation Provider. Add replace-with tag in your gwt modle file telling GWT to use the Validator you just defined (see Validation.gwt.xml)

<inherits name="org.hibernate.validator.HibernateValidator" />
<replace-with
    class="com.google.gwt.sample.validation.client.SampleValidatorFactory">
    <when-type-is class="javax.validation.ValidatorFactory" />
</replace-with>

Source

Deathblow answered 11/2, 2011 at 7:46 Comment(2)
Too bad that this is not yet tied to the Editor framework, to provide the validation messages next to the input fields.Gecko
As of gwt-2.4.0-rc1 the attempt is already made: see com.google.gwt.editor.client.impl.BaseEditorDriver.setConstraintViolations(...) impossible to use on the client side though due to weird generics in method argument.Rotifer
H
2

I have done something similar to this by adding an additional DriverWrapper class that takes the existing Driver and Validator and adds a flush method that first delegates to the underlying Driver flush and then calls the Validator. Any errors returned are then added to the Editors using a new visitor, similar to the way the existing Flusher works. This means the existing decorators that display the errors next to the fields continue to work.

/**
 * Wraps a Driver and provides validation using gwt-validation (JSR 303).
 * When calling flush, this will use the provided IValidator to validate the data
 * and use the InvalidConstraintValidationVisitor to add the errors to the delegates.
 * @see InvalidConstraintValidationVisitor
 * @param <T> the data type for the editor
 * @param <D> the driver type
 */
public class ValidationDriverWrapper<T extends IsValidatable<T>, D extends EditorDriver<T>> {
private IValidator<T> validator;
private D driver;

/**
 * Constructor, both parameters are required.
 * @param driver The driver to use to flush the underlying data.
 * @param validator The validator to use to validate the data.
 */
public ValidationDriverWrapper(D driver, IValidator<T> validator) {
    this.validator = validator;
    this.driver = driver;
}

/**
 * Flushes the underlying Driver and then calls the validation on the underlying Validator, cascading errors as EditorErrors
 * onto the delegates, using InvalidContraintValidationVisitor.
 */
public void flush()
{
    T data = driver.flush();
    Set<InvalidConstraint<T>> errors = validator.validate(data);
    Set<InvalidConstraint<T>> extraErrors = data.validate();
    if(extraErrors != null && !extraErrors.isEmpty())
    {
        errors.addAll(extraErrors);
    }
    driver.accept(new InvalidConstraintValidationVisitor<T>(errors));
}
Hallsy answered 12/8, 2011 at 5:31 Comment(4)
Did something similar to provide on-the-fly validation. Works pretty well thanks to the editor visitor pattern.Columella
@logan, could you please show how you implemented on-the-fly validation? I'm having hard time doing that in concise manner in case of nested editors.Gigantism
@ruslan - I've been thinking about making it open source, but I haven't found the time yet. You still interested?Columella
@logan, sure. If you create Google Code project I can take a loot at it.Gigantism
T
1

I've got exaclty the same problem.

The documentation is not clear about it.

What I'm currently doing is to recreate some widgets by extending them with widget I want to copy. After it I implement LeafValueEditor and HasEditorDelegate to override getValue().

In getValue(), use your validator and call if needed yourDelegate.recordError().

Something like this: a little integer box which check that value is not greater than 10.

public class IntegerField extends ValueBox<Integer> implements LeafValueEditor<Integer>, HasEditorDelegate<Integer>
{
private EditorDelegate<Integer> delegate;

public IntegerField()
{
    super(Document.get().createTextInputElement(), IntegerRenderer.instance(), IntegerParser.instance());

    setStyleName("gwt-TextBox");

}

@Override
public Integer getValue()
{
    Integer value = super.getValue();

    if (value > 10)
    {
        delegate.recordError("too big integer !", value, null);
    }

    return value;
}

@Override
public void setValue(Integer value)
{
    super.setValue(value);
}

@Override
public void setDelegate(EditorDelegate<Integer> delegate)
{
    this.delegate = delegate;
}
}

The best approach is to simply add custom verification to existing widgets and not override them but I don't know how to do it !

Tyson answered 12/11, 2010 at 14:22 Comment(1)
I want to do my validation external, and later on add my validation errors. For the moment, I have created some custom code inside each editor to bind a propertyPath to a widget. However, this information is already present somewhere in the system, I just cannot seem to get it out of the system.Gecko
M
0

Validation doesn't exist in GWT yet, it's coming in the next release AFAIK. The current support for validation in GWT is server side JSR-303 and client side JSR-303 support is coming soon. Therefore, you'll have to do the validation manually. If you follow the MVP model, I think this validation logic would live in your Presenter.

Maurer answered 6/11, 2010 at 0:22 Comment(1)
What I am trying to do, is plugging my validation system into the GWT editor framework. You have operations like recordError and showErrors on the editors. I am looking for the correct place to trigger the validation and connect my validation errors to the paths that I use to configure my editor with.Gecko
F
0

It's messy but to get the path of an Editor you could implement HasEditorDelegate (which will give you access to the delegate) and then cast the Delegate to AbstractEditorDelegate, which has a public String getPath() method.

I don't think it is possible to do external validation though; validation happens in the editor at the point that a value is read from the field (see ValueBoxEditor - this editor uses getDelegate().recordError to raise an error). One option I did consider was to use the AbstractEditorDelegate access to call flushErrors(List) and to create that list of EditorErrors myself. To do that you need to know each of your field paths; hardcoding them is hardly desirable, but I don't see a way of looking up the Field by the edited property or anything like that.

An alternative approach that might bear looking into is this submission for round trip validation using the requestfactory:

http://groups.google.com/group/google-web-toolkit-contributors/browse_thread/thread/5be0bda80547ca5a

Foochow answered 10/2, 2011 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.