如何在 Vaadin 的文本字段上创建实时验证器?

How to create a real time validator on a text field in Vaadin?

我目前使用的是 Vaadin 7.3+ 并希望在用户实时输入时在文本字段中进行验证。

这是我到目前为止尝试过的:

textField.setTextChangeEventMode(TextChangeEventMode.LAZY);
textField.setNullRepresentation("");

textField.addTextChangeListener(new FieldEvents.TextChangeListener() {
    @Override
    public void textChange(FieldEvents.TextChangeEvent event) {
        for (Validator v : textField.getValidators()) {
            try {
                v.validate(event.getText());
            } catch (InvalidValueException e) {
                log.warn("validation error: " + e.getMessage() + " and value was: {}", event.getText());
            }
        }
    }
});

问题是,尽管所有验证器都在执行并且正在完成验证,但直到焦点离开该字段(即用户按下回车键或单击其他地方)后,才会呈现红色错误指示器。我尝试添加 textField.markAsDirty 但这没有用。有谁知道这个问题的解决方案?或者一般来说有更好的解决方案来在文本字段上创建实时验证器?

提前感谢您的宝贵时间和意见:-)

这里的问题是,事件发送了文本,但实际上并没有修改输入的值。解决这个问题的最简单方法是设置值。例如

addTextChangeListener(new FieldEvents.TextChangeListener() {
    @Override
    void textChange(FieldEvents.TextChangeEvent event) {
        final textField = event.source as TextField
        textField.value = event.text
    }
})

这只会触发字段和验证器的更改,所有这些都会按预期传递给客户端。

编辑

如您在评论中所述,应保留光标位置。您可以使用所需的任何方式验证事件中的文本。这里的关键点是,只需设置字段的 componentError 以获得该字段的错误。

@Override
void textChange(FieldEvents.TextChangeEvent event) {
    final tf = event.source as TextField
    try {
        tf.validate(event.text) // this works in groovy!  not java.
        tf.setComponentError(null)
    }
    catch (InvalidValueException e) {
        tf.setComponentError(new SystemError(e))
    }
}

这个直接的变通解决方案似乎工作正常,尽管它很不优雅。

textField.setTextChangeEventMode(TextChangeEventMode.LAZY);
textField.setNullRepresentation("");

textField.addTextChangeListener(new FieldEvents.TextChangeListener() {
    @Override
    public void textChange(FieldEvents.TextChangeEvent event) {
        try {
            textField.setValue(event.getText());

            // workaround cursor position problem
            textField.setCursorPosition(event.getCursorPosition());

            textField.validate();
            } catch (InvalidValueException e) {
                log.warn("validation error: " + e.getMessage() + " and value was: {}", delegate.getValue());
            }
    }
});

Vaadin 核心中的验证器并非设计为在键入时工作,这对于 RIA 框架来说是一种耻辱。这有望在即将发布的版本中得到修复。今天让它与核心组件一起工作有点棘手,但可行。如果您的服务器和客户端之间存在一些延迟,您自己的解决方案可能会出现一些用户体验问题 - 如果用户在执行验证器时再次开始重新输入,则光标可能会跳到意想不到的位置。我在 Viritin add-on. By using its AbstractForm (or raw MBeanFieldGroup) together with MTextField this should work pretty well and without any configuration. You can try that solution with e.g. this example.

中为此做了很多工作

Take a look 在 Vaadin 文档中。如果我没看错,将您的字段设置为即时模式应该没问题。有时建议允许空值以避免不必要的警告。

TextField field = new TextField("Name");
 field.addValidator(new StringLengthValidator(
"The name must be 1-10 letters (was {0})",
1, 10, true));
field.setImmediate(true);
field.setNullRepresentation("");
field.setNullSettingAllowed(true);