Validation on blur

What is the way of getting validation errors to show e.g. on tabbing out from a text field?

If I have a simple binder-field-validator setup I can see the validator on the field fail but no error show up until I call binder.validate() from a button.

I feel like I’m missing something simple here…

It should work like that by default. Can you give a simple example?

@Route("test")
@RouteScoped
public class TestView extends HorizontalLayout {

	@PostConstruct
	public void init() {
		Binder<Data> binder = new Binder<>();
		TextField field = new TextField();
		binder.forField(field).withValidator(new FailingValidator()).bind(Data::getData, Data::setData);
		add(field);

		Button button = new Button("X", e -> binder.validate());
		add(button);
	}

	private class FailingValidator implements Validator<String> {

		@Override
		public ValidationResult apply(String value, ValueContext context) {
			System.out.println("fail");
			return ValidationResult.error("fail");
		}

	}

	private class Data {
		private String data;

		public String getData() {
			return data;
		}

		public void setData(String data) {
			this.data = data;
		}

	}

}

I enter something in the field and tab out. I see “fail” in the console log but nothing under the component. I click the button and see “fail” in the console and this time the validation error shows up

I tried with your example and I will get the fail error message under the component right after I tab out of it. Here’s my full view code:

package org.vaadin.olli;

import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.ValidationResult;
import com.vaadin.flow.data.binder.Validator;
import com.vaadin.flow.data.binder.ValueContext;
import com.vaadin.flow.router.Route;

@Route("")
public class MainView extends VerticalLayout {

    public MainView() {
        Binder<Data> binder = new Binder<>();
        TextField field = new TextField();
        binder.forField(field).withValidator(new FailingValidator())
                .bind(Data::getData, Data::setData);
        add(field);
    }

    private class FailingValidator implements Validator<String> {

        @Override
        public ValidationResult apply(String value, ValueContext context) {
            System.out.println("fail");
            return ValidationResult.error("fail");
        }

    }

    private class Data {
        private String data;

        public String getData() {
            return data;
        }

        public void setData(String data) {
            this.data = data;
        }
    }

}

Can you toss in the

		<dependency>
			<groupId>com.vaadin</groupId>
			<artifactId>flow-server-compatibility-mode</artifactId>
		</dependency>

and see if it still works?

Yep, still works

Hmm, works for me too but only without the compatibility mode for some reason.

BTW. The deployment time went up quite sharply with all the npm stuff going on, is there some documentation somewhere that could give hints as what to do to quicken the deployment cycle?

And for some reason the plain TextField sample works now but my Composite

that has a simple TextField-extension never sets the “invalid”-attribute correctly on the field so the validation error shows up in the DOM but the style is max height 0.

Hmm. I’m still seeing this issue. If I use the latest in 13.x, the “fail” shows up. If I use the latest 14.x, height is 0 :-/

To be clear - there is no need in 14.x to manually enable the error indicator, right? The binder should take care of all the plumbing?

Apparently this behavior broke between 14.0.5 and 14.0.6. I assume it is by accident since it would be quite a major change in expected behavior for a minor version release to have to set the error flag yourself?

Opened an issue, https://github.com/vaadin/framework/issues/11807 for it