How to edit two comboboxes with a listener on one in a Vaadin 8 grid editor

I have two ComboBoxes in my editable Grid where the second ComboBox based on the first one. So for example you would have Car Make and then Car Model. When you change the make combobox the model combobox then changes accordingly.

With that in mind I have:

ComboBox<String> makeComboBox = new ComboBox<String>();
ComboBox<String> modelComboBox = new ComboBox<String>();

Specifically:

grid.addColumn(CarRental::getPerson)
    .setEditorBinding(binder.forField(personComboxBox).bind(CarRental::getPerson, CarRental::setPerson));
grid.addColumn(CarRental::getMake)
    .setEditorBinding(binder.forField(makeComboxBox).bind(Car::getMake, Car::setMake));
grid.addColumn(CarRental::getModel)
    .setEditorBinding(binder.forField(modelComboxBox).bind(Car::getModel, Car::setModel));

The key here is that I want the modelComboBox to change if the makeComboBox is changed. In other words if you select Honda then I want the model ComboBox to change to Fit, Civic, Accord, and so on. To do this I add a SelectionListener (but it could also be a valueChangeListener, it doesn’t matter, the effect is still the same).

Specifcally I have:

makeComboBox.addSelectionListener(event -> 
{
	modelComboBox.clear();
    modelComboBox.setItems(getModelsBasedOnMake(makeComboBox.getValue()));
    // Assuming someone has just edited the make value, 
	// say changed from Toyota to Honda, then I want the model selected to be empty 
});

Because the ComboBox can be different I’ve added some logic to update the components on the OpenListener for the Grid Editor. Specifically I do:

grid.getEditor().addOpenListener(open ->
{
   ...
   CarRental selectedCarRental = (CarRental)event.getBean();
   makeComboBox.setItems(makeList);
   modelComboBox.setItems(getModelsBasedOnMake(selectedCarRental.getMake()));
});

The problem here is that the modelComBoxbox tends to be unselected because if you look at it there’s no guarantee which value it will be because there is a conflict.

I looked at temporarily disabling the selectionListener but this all the remove listeners have been deprecated with Vaadin 8. Therefore how can I setup the grid to be able to edit both the car make and model in the grid?

You can still remove listeners; you just need to take the returned [Registration]
(https://vaadin.com/api/8.0.0/com/vaadin/shared/Registration.html) object from the addXListener method instead of using removeListener in the Component.

-Olli

Let me ask another question then. Let’s say I’ve got a Grid Editor and there is a ValueChangeListener on that field so that if the value is changed and say field2 is empty it will put some value, how can I do this in the Grid?

So for example In the above code I have:

personComboBox.addValueChangeListener(change -> 
{
    // By default I when you select John we pick his car for him
    if(person.equals("John") && noCarSelected())
	{
	    makeComboBox.setValue("Honda");
		modelComboBox.setValue("Civic");
    }
});

This doesn’t appear possible because if there is no make or model selected and I try to doubleclick on that row it will automatically select them for me when the binder sets the value which I do not want (this is a bad example but it can happen that we removed the defaulted options and nothing is selected and we want it to remain at nothing. In either case it looks like the edit is not grabbing the correct data since it’s empty on the table but now has a value in the editor.

I tried to remove the listener manually with the Registration (thanks for that tip btw) however I’m still faced with the problem that the Grid Editor will fire the listener as soon as the binder sets the value which I don’t want, I only want it to fire those listeners after it’s open.

I also can’t use BlurListener because I need to update it as the person is editing the values, in this example when they select the person John.

It’s a tricky situation. If I understand your scenario correctly, I guess one option could be that you you create a custom Component that contains the selectors for both values (on a HorizontalLayout probably) and put that in a ComponentColumn instead of using a Grid Editor and Binder? That way you will be in full control of the displayed values and events.

-Olli

My feeling is that it’s not possible to have listeners in the Grid Editor where you have any logic that combines more than one field (column). At least not using the binder because the binder will cause the listeners to be fired. And there’s no way to temporarily disable the listeners while the Grid Editor is being loaded.

Would that be a correct assessment of the situation?

I can’t say for sure that “there’s no way” just because I don’t know of a way, but at least generally the logic with Grid Editor would be like that, yes.

Are you using bufferd or un-buffered editor. If it is the unbuffered one, one approach to this would be not to use listeners with ComboBoxes at all. Instead you could use GridFastNavigation add-on, which has events for edits, so you could do the updating of the other ComboBox in that edit event instead. But this is only one approach, there are probably others too.

I did look at GridFastNavigation but it resulted in some other weird issues. Although I like some of the added functionality it caused other issues for me…