Showing GWT validation errors using Editor Framework

4.2k views Asked by At

I do GWT client side validation and I've a problem of how to show validation errors which are returned by validator. I debugged it and I can see that the set contains errors but driver doesn't show them. SimpleBeanEditorDriver is used.

Entry Entry = driver.flush();
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Entry>> violations = validator.validate(Entry, Default.class);
if (violations.size() > 0) {
   driver.setConstraintViolations(new ArrayList<ConstraintViolation<?>>(violations));
   ... 
}

Tested on GWT ver. 2.4 and 2.5

The code is written according to https://developers.google.com/web-toolkit/doc/latest/DevGuideValidation but they're not using editors.

Does anybody make it work together GWT validation and Editors ? May be somebody can give links to good examples of it ? I couldn't find any working ones. Any help are welcomed!

2

There are 2 answers

0
Chris Hinshaw On

Here is a simple example of how we are using editors/HasEditorError and ConstraintViolations. I have also included a sample from our ValueBoxEditorDecorator which allows us to layout error message.

Our activity

 @Override
  public void onSave() {
    RequestFactoryEditorDriver<DashboardModelProxy, ?> driver = display.getDriver();
    RequestContext context = driver.flush();
    context.fire(new Receiver<Void>() {

      @Override
      public void onSuccess(Void response) {
        Place previousPlace = clientFactory.getPlaceController().getPreviousPlace();
        clientFactory.getPlaceController().goTo(previousPlace);
      }

      @Override
      public void onFailure(ServerFailure error) {
        display.showError(error.getMessage());
      }

      @Override
      public void onConstraintViolation(Set<ConstraintViolation<?>> violations) {
        display.getDriver().setConstraintViolations(violations);
      }
    });
  }

Sample from our view.

/**
 * Name component for the name of the analytics operation.
 * This also implements {@link HasEditorErrors so it can show
 * constraint violations when an error occurs.
 */
@UiField
ValueBoxEditorDecorator<String> name;

UIBinder example using the error location.

  <t:ValueBoxEditorDecorator errorLocation="RIGHT" ui:field="name">
            <t:valuebox>
                <g:TextBox />
            </t:valuebox>
  </t:ValueBoxEditorDecorator>

The ValueBoxEditorDecorator we are using.

import java.util.List;

import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.editor.client.EditorError;
import com.google.gwt.editor.client.HasEditorErrors;
import com.google.gwt.editor.client.IsEditor;
import com.google.gwt.editor.client.adapters.TakesValueEditor;
import com.google.gwt.editor.ui.client.adapters.ValueBoxEditor;
import com.google.gwt.uibinder.client.UiChild;
import com.google.gwt.uibinder.client.UiConstructor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.ValueBoxBase;
import com.google.gwt.user.client.ui.ValueListBox;

/**
 * This is a copy of the original ValueBoxEditorDecorator in the gwt source The
 * reason we are not using it is because it did not support laying out the error
 * panel in a different location.
 * 
 * 
 * A simple decorator to display leaf widgets with an error message.
 * <p>
 * <h3>Use in UiBinder Templates</h3>
 * <p>
 * The decorator may have exactly one ValueBoxBase added though an
 * <code>&lt;e:valuebox></code> child tag.
 * <p>
 * For example:
 * 
 * <pre>
 * &#064;UiField
 * ValueBoxEditorDecorator&lt;String&gt; name;
 * </pre>
 * 
 * <pre>
 * &lt;e:ValueBoxEditorDecorator ui:field='name'>
 *   &lt;e:valuebox>
 *     &lt;g:TextBox />
 *   &lt;/e:valuebox>
 * &lt;/e:ValueBoxEditorDecorator>
 * </pre>
 * 
 * @param <T>
 *            the type of data being edited
 */

public class ValueListBoxEditorDecorator<T> extends Composite implements HasEditorErrors<T>, IsEditor<TakesValueEditor<T>> {

    /**
     * The location of the text relative to the paging buttons.
     */
    public static enum ErrorPanelLocation {
        LEFT, RIGHT;
    }

    SimplePanel contents = new SimplePanel();

    @Ignore
    Label errorLabel = new Label();

    HorizontalPanel layout = new HorizontalPanel();

    private TakesValueEditor<T> editor;

    /**
     * Constructs a ValueBoxEditorDecorator.
     */
    @UiConstructor
    public ValueListBoxEditorDecorator(ErrorPanelLocation errorLocation) {
        initWidget(layout);
        setStyleName("gwt-ValueBoxEditorDecorator");
        errorLabel.setStyleName("gwt-ValueBoxEditorDecorator-error");
        errorLabel.getElement().getStyle().setDisplay(Display.NONE);

        if (errorLocation == ErrorPanelLocation.RIGHT) {
            layout.add(contents);
            layout.add(errorLabel);
        } else {
            layout.add(errorLabel);
            layout.add(contents);
        }
    }

    /**
     * Constructs a ValueBoxEditorDecorator using a {@link ValueBoxBase} widget
     * and a {@link ValueBoxEditor} editor.
     * 
     * @param widget
     *            the widget
     * @param editor
     *            the editor
     */
    public ValueListBoxEditorDecorator(ValueListBox<T> widget, TakesValueEditor<T> editor) {
        this(ErrorPanelLocation.RIGHT);
        contents.add(widget);
        this.editor = editor;
    }

    /**
     * Returns the associated {@link ValueBoxEditor}.
     * 
     * @return a {@link ValueBoxEditor} instance
     * @see #setEditor(ValueBoxEditor)
     */
    public TakesValueEditor<T> asEditor() {
        return editor;
    }

    /**
     * Sets the associated {@link ValueBoxEditor}.
     * 
     * @param editor
     *            a {@link ValueBoxEditor} instance
     * @see #asEditor()
     */
    public void setEditor(ValueBoxEditor<T> editor) {
        this.editor = editor;
    }

    /**
     * Set the widget that the EditorPanel will display. This method will
     * automatically call {@link #setEditor}.
     * 
     * @param widget
     *            a {@link ValueBoxBase} widget
     */
    @UiChild(limit = 1, tagname = "valuebox")
    public void setValueBox(ValueBoxBase<T> widget) {
        contents.add(widget);
        setEditor(widget.asEditor());
    }

    public void clearErrors() {
        errorLabel.setText("");
        errorLabel.getElement().getStyle().setDisplay(Display.NONE);
    }

    /**
     * The default implementation will display, but not consume, received errors
     * whose {@link EditorError#getEditor() getEditor()} method returns the
     * Editor passed into {@link #setEditor}.
     * 
     * @param errors
     *            a List of {@link EditorError} instances
     */
    public void showErrors(List<EditorError> errors) {
        StringBuilder sb = new StringBuilder();
        for (EditorError error : errors) {
            if (error.getEditor().equals(editor)) {
                sb.append("\n").append(error.getMessage());
            }
        }

        if (sb.length() == 0) {
            clearErrors();
            return;
        }

        errorLabel.setText(sb.substring(1));
        errorLabel.getElement().getStyle().setDisplay(Display.INLINE_BLOCK);
    }
}
0
apetrelli On

This wiki might help you: https://github.com/apetrelli/gwt-integration/wiki/GWT-Integration-Editor although it integrates Editor, Validator and RequestFactory. I created a Maven archetype that uses it: https://github.com/apetrelli/samplegwt