Chris
Chris

Reputation: 984

How do I pre-select items in a Vaadin 21 Grid? Selection is not displayed in the UI

I have defined a layout that implements BeforeEnterObserver. In the beforeEnter method, I load an object instance from the database. The instance has relations to other objects. Also inside this method, I call a method of another Layout, that sets the bean and tries to preselect items in a Grid:

    public void setBean(BeanClass bean) {
        binder.setBean(bean);
        relationGrid.deselectAll();
        for(Person person : bean.getRelated()) {
            relationGrid.getGrid().select(person);
        }
        Set<Person> selected = involvedGrid.getGrid().getSelectedItems();
    }

That last line is there for debugging. I can see, that the bean that has been loaded is correctly selecting the related instance.

The Grid is defined within it's own class inside a layout and has multiselection and no select-all checkbox and a search field:

grid.setSelectionMode(Grid.SelectionMode.MULTI);
GridMultiSelectionModel<Person> selectionModel = (GridMultiSelectionModel<Person>) grid.getSelectionModel();
selectionModel.setSelectAllCheckboxVisibility(GridMultiSelectionModel.SelectAllCheckboxVisibility.HIDDEN);

The Grid layout is injected into the form view, which is injected into the edit view.

Now when showing the edit view in the Browser, the related object in the Grid are not checked. I have configured a button inside the edit view, to show the selected items, for debugging purposes:

        cancel.addClickListener(e -> {
                Set<Person> selectedPersons = form.getRelatedGrid().getSelectedItems();
                for(Person person : selectedPersons)
                    Notification.show(person.getDisplayName());
        });

If I click the button, it correctly shows the name of the related person. If I then select another person and click again, it correctly shows both selected persons as notifications, but in the Grid only the second one is selected.

The fields of the form are correctly filled and as shown above I directly afterwards take care of the relationships.

I also tried to enable Push-Mode

@Push
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {

    public static void main(String[] args) {
                SpringApplication.run(Application.class, args);
    }
}

This does not change the behaviour of the grid.

For simplification and after discussion with Tatu, I made a test-view. The same problem still exists.

@Route(value = "event/:id([0-9]+)/edit_test", layout = MainLayout.class)
public class EditEventTest extends VerticalLayout implements BeforeEnterObserver, AfterNavigationObserver {

    private final EventRepository eventRepository;
    private final PersonRepository personRepository;

    private Long id;
    private Event event;

    private final TextField title = new TextField("Title");
    private final Grid<Person> persons = new Grid<>(Person.class, false);

    private final Button save = new Button("Save");
    private final Button test = new Button("Test");

    private Binder<Event> binder = new Binder<>(Event.class);

    @Autowired
    public EditEventTest(EventRepository eventRepository, PersonRepository personRepository) {
        this.eventRepository = eventRepository;
        this.personRepository = personRepository;
    }

    @Override
    public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
        id = Long.valueOf(beforeEnterEvent.getRouteParameters().get("id").orElseThrow(NotFoundException::new));
        Optional<Event> result = eventRepository.findById(id);
        this.event = result.orElseThrow(() -> new NoSuchRecordException("Could not find Event with id " + id));
    }

    @Override
    public void afterNavigation(AfterNavigationEvent event) {
        buildView();
        updateView();
    }

    private void buildView() {

        persons.setSelectionMode(Grid.SelectionMode.MULTI);
        GridMultiSelectionModel<Person> selectionModel = (GridMultiSelectionModel<Person>) persons.getSelectionModel();
        selectionModel.setSelectAllCheckboxVisibility(GridMultiSelectionModel.SelectAllCheckboxVisibility.HIDDEN);
        persons.addColumn(Person::getDisplayName).setHeader("Name");
        GridListDataView<Person> dataView = persons.setItems(personRepository.findAll());

        FormLayout form = new FormLayout();
        add(form);
        form.add(title);
        form.add(persons);

        binder.setBean(event);
        binder.bindInstanceFields(this);

        HorizontalLayout buttonLayout = new HorizontalLayout();
        buttonLayout.addClassName("button-layout");
        save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        buttonLayout.add(save);
        buttonLayout.add(test);
        add(buttonLayout);

        test.addClickListener(e-> {
            for (Person p : persons.getSelectedItems())
                Notification.show(p.getDisplayName());
        });

    }

    private void updateView() {
        persons.deselectAll();
        for (Person person : event.getInvolved())
            persons.select(person);
    }

}

I also tried to move buildView()to constructor and binder.setBean(event) to updateView(). The problem is still there.

What am I missing here or is this a bug?

Upvotes: 1

Views: 594

Answers (1)

Tatu Lund
Tatu Lund

Reputation: 10623

Your code looks ok for me by brief glance. I just would recommend to move fetching of the data to afterNavigation from beforeEnter, but it should not affect the outcome. This is something you should consider in wider scope, i.e. not to load data from backend, before it is certainly needed. You may for example in other views or in this view in future have access control in beforeEnter. Hover this is not related to your actual problem.

This method can be probably simplified

private void updateView() {
    persons.deselectAll();
    for (Person person : event.getInvolved())
        persons.select(person);
}

To

private void updateView() {
    persons.asMultiSelect().setValue(event.getInvolved());
}

But again I do not expect it to change the behavior. If it does there is a bug in Grid#select, as in multiselect mode it should not reset previous selections.

Upvotes: 1

Related Questions