Reputation: 984
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
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