Vaadin 24 : MultiSelectComboBox overlay closes when selecting an item?

I use MultiSelectComboBox on multiple pages, but only one page has this problem. The createTableEditorMultiSelect method for this page is different from the other pages. On this page, the two fields are stored in separate tables, not in the same table as the parent entity.

@OneToMany(
    cascade = CascadeType.ALL,
    mappedBy = "parent",
    fetch = FetchType.EAGER,
    orphanRemoval = true
)
@Fetch(FetchMode.SUBSELECT)
private Set<ToolClassA> toolClassesA = new HashSet<>();

@Transient
private Set<ToolClassA> backupToolClassesA = new HashSet<>();
// used to temporarily hold values when another field changes

@OneToMany(
    cascade = CascadeType.ALL,
    mappedBy = "parent",
    fetch = FetchType.EAGER,
    orphanRemoval = true
)
@Fetch(FetchMode.SUBSELECT)
private Set<ToolClassB> toolClassesB = new HashSet<>();

Here’s my method for creating a multi select:

select.addSelectionListener(e -> {
    boolean refreshRow = false;

    if (currentItem != null && gridEditor != null
            && gridEditor.getItem() != null
            && gridEditor.getItem().equals(currentItem)) {

        Set<String> selected = e.getValue();

        // If user selects "ALL", clear other selections and set special value in the entity
        if (selected.contains("ALL")) {
            if ("columnA".equalsIgnoreCase(column.getKey())) {
                Set<ToolClassA> values = new HashSet<>();
                values.add(convert("ALL")); // placeholder for special "ALL" value
                currentItem.setToolClassesA(values);
                refreshRow = true;
            }

            if ("columnB".equalsIgnoreCase(column.getKey())) {
                Set<ToolClassB> values = new HashSet<>();
                values.add(convert("ALL"));
                currentItem.setToolClassesB(values);
                refreshRow = true;
            }
        }

        // mark field and row as edited
        markFieldEdited(currentItem, column.getKey(), e.getOldValue(), e.getValue());
        markRowEdited(currentItem);
        updateEditorStyle(currentItem, column);

        if (refreshRow) {
            binder.readBean(currentItem);
        }

        persistEditorValues();
    }
});

I added a breakpoint to see which line causes the overlay to close, but the overlay does not close until the method finishes running

Here’s how I define the editor for this column:

// Create the MultiSelectComboBox for this column
toolMultiSelect = createTableEditorMultiSelect(column, toolOptions, null);

binder.forField(toolMultiSelect)
      .withConverter(toolConverter) // generic tool converter
      .withValidator(selectedTools -> ValidationUtils.validateNotNull(selectedTools, canSkipValidation()), 
                     "Required") // generic validation
      .bind("toolCollection"); // the name of the entity property (a Set/Collection)

// Set the editor component for the column
column.setEditorComponent(toolMultiSelect);

How can I debug this further to pinpoint why the overlay closes?

It’s pretty hard to guess based on the given snippet. That would be my first guess.

So it turns out this method is causing the behavior.
I’m not sure why it didn’t behave this way in Vaadin 14, but in Vaadin 24 it causes the overlay to close:
persistEditorValues

I’m not entirely sure why the persistEditorValues method is needed. My teammate wrote it to handle some edge case, and I need some more time to fully understand what the method is trying to do.

private void persistEditorValues() {
    Object backupValidationFailedItem = validationFailedItem;
    validationFailedItem = null;
    grid.getEditor().save();
    if (backupValidationFailedItem != null
            && backupValidationFailedItem == selectedItem) {
        validationFailedItem = backupValidationFailedItem;
        forceValidation = true;
    }

    // Reopen the editor if it was closed during save,
    // so the user can continue editing the same row
    if (!grid.getEditor().isOpen()) {
        grid.getEditor().editItem(selectedItem);
    }
}

I just realized my text field is also acting weird.
As long as I enter 1 character, it just exit the edit state.
It did not happen in Vaadin 14 with this code, what could be the issue?:

private TextField createTableEditorTextField(
        Column<?> column,
        Grid<?> grid,
        Grid.Editor<?> gridEditor,
        Object selectedItem) {

    TextField editorField = new TextField();
    editorField.setSizeFull();
    editorField.setValueChangeMode(ValueChangeMode.EAGER);

    editorField.addValueChangeListener(e -> {
        if (selectedItem != null
                && gridEditor != null
                && gridEditor.getItem() != null
                && gridEditor.getItem().equals(selectedItem)) {

            setFieldEdited(selectedItem, column.getKey(), e.getOldValue(), e.getValue(), false);
            setTableRecordEdited(selectedItem);
            setColumnEditorStyle(selectedItem, column);

            grid.getEditor().save();
            if (!grid.getEditor().isOpen()) {
                grid.getEditor().editItem(selectedItem);
            }
        }
    });

    column.setEditorComponent(editorField);
    return editorField;
}

Well… removing the save () would help a lot. I would guess that closes the editing. Using eager + value change is triggered immediately.

I would suggest to rebuild the whole editor with a Binder. Looks like a really hacky solution overall.

1 Like