vaadin

addBlurListener() at CustomField don't work


I am not a professional developer, programming is just my hobby.

So I ask for help in understanding the following problem.

I use

<properties>
    <java.version>21</java.version>
    <vaadin.version>24.4.12</vaadin.version>
</properties>

I created a class that extends CustomField:

@FieldDefaults(level = AccessLevel.PRIVATE)
public class ValueCustomComponent extends CustomField<ValueDTO> {
    NumberField numberField;
    ComboBox<String> comboBox;
    ValueDTO value = new ValueDTO();
    public ValueCustomComponent() {
        initialize();
    }
    private void initialize() {
        this.numberField = new NumberField();
        this.comboBox = new ComboBox<>();
        comboBox.setItems(List.of("First Value", "Second Value", "Third Value"));
        comboBox.setAllowCustomValue(true);
        numberField.getElement().setAttribute("disabled", true);
        comboBox.addBlurListener(comboBoxBlurEvent -> {
            if(comboBox.getValue() != null && !comboBox.getValue().equals(value.getDrug())){
                numberField.getElement().setAttribute("disabled", false);
            }
        });
        setValues();
        add(comboBox, new Text(" "), numberField);
    }
    private void setValues() {
        if (value.getDrug() != null) {
            comboBox.setValue(value.getDrug().toString());
        }
        if (value.getAmount() != null) {
            numberField.setValue(value.getAmount());
        }
    }
    @Override
    protected ValueDTO generateModelValue() {
        value.setDrug(comboBox.getValue());
        value.setAmount(numberField.getValue());
        return value;
    }
    @Override
    protected void setPresentationValue(ValueDTO valueDTO) {
        comboBox.setValue(valueDTO.getDrug().getValue());
        numberField.setValue(valueDTO.getAmount());
    }
}
`

Now I'm trying to get a notification when this component loses focus:

@Route(value = "test")
@FieldDefaults(level = lombok.AccessLevel.PRIVATE)
public class TestView extends VerticalLayout {

    public TestView() {
       ValueCustomComponent valueCustomComponent = new ValueCustomComponent();
       valueCustomComponent.addBlurListener(this::onBlur);
       add(valueCustomComponent);
    }
    private void onBlur(BlurNotifier.BlurEvent<CustomField<ValueDTO>> customFieldBlurEvent) {
        showNotification(customFieldBlurEvent.getSource().getValue().toString());
    }
    private void showNotification(String value) {
        Notification notification = new Notification(value, 2000, Notification.Position.TOP_CENTER);
        notification.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
        notification.open();
    }
}

But onBlur() method is never called.

Why doesn't the default implementation of addBlurListener() work?

What should I do to get addBlurListener() working?

I tried to find information in the Vaadin documentation and forum, as well as on stackoverflow, but without success.


Solution

  • This is because of how the DOM events work, not so much related to Vaadin itself.

    Your custom component essentially has a container element with multiple child elements/components within (comboBox and numberField). The children do become active when focused, however, the ValueCustomComponent element never does because the active focus does not automatically bubble up to parent elements.

    // not real html, just a visual to show basic dom structure
    <ValueCustomComponent>
      <ComboBox />
      <NumberField />
    </ValueCustomComponent>
    

    You can manually fire a blue event from the ValueCustomComponent class like this:

    fireEvent(new BlurEvent<ValueCustomComponent>(this, true));
    

    You will need to find a way to track focus (via focus and blur listeners on the comboBox and numberField fields) and manually fire a blur event when you're confident the focus has left one of your child fields and is did not move to an another child.