ValueChangeListener and ComboBox doesn't fire with null value

I have a ComboBox (actually it is a Select and I need to fix that soon) with a ValueChangeListener. When I change the value the listener fires perfectly. So that’s good. But I often want to set it back to the empty or null value. In that case the listener does not fire. Should it? I hope there’s a way to make it fire.

I have the following settings on the field:

setMultiSelect(false);
setNullSelectionAllowed(true);
setImmediate(true);
setBuffered(true);

This is using
Vaadin 7.5.6
Java 1.7
Tomcat 7

Thanks for any help

Tested it with the following code on 7.5.6 and 7.5.7:

protected void init(VaadinRequest request) {
    ComboBox comboBox = new ComboBox("", Arrays.asList("f", "ff"));
    comboBox.addValueChangeListener(e -> Notification.show("" + e.getProperty().getValue()));
    comboBox.setMultiSelect(false); // this is deprecated and shouldn't be used anyways
    comboBox.setNullSelectionAllowed(true);
    comboBox.setImmediate(true);
    comboBox.setBuffered(true);
    setContent(comboBox);
}

Works perfectly.

Thanks for the reply, Michael.

I’ve been over this again and the only difference between your code and mine that I can see is that setBuffered(true) is actually setBuffered(false) in my code, I reported that incorrectly earlier, sorry. I need it to be setBuffered(false) or the value is not sent to the server when it changes. To check this I tried it both ways and when I set the drop-down to a real value it works with setBuffered(false) but doesn’t work with setBuffered(true). I also changed it to a ComboBox to eliminate any confusion from my using the deprecated Select.

Because of this setBuffered thing I wonder if I did not explain the problem well enough. You have setBuffered(true) which cannot fire the ValueChangeListener until the field is committed and I don’t want to wait for a commit. I need to fire the listener immediately because other values on the form need to change. Does that change your thinking about this?

I’ve done some more work to try and track this down but I still don’t see it passing the null value back. With those settings (MultiSelect false NullSelectionAllowed true Immediate true Buffered false) in place I turned on the ?debug in the browser and noted the behaviour, specifically the debug message log. There are entries generated when I open the drop down (displaying the choices) and when I actually pick an ordinary choice. But when I pick the top choice, the empty one, nothing is logged. So it isn’t sending anything back to the server.
Using the ?debug window I inspected the field and found:

Id 73
Connector ComboBoxConnector
Widget VFilterSelect
Caption Size
Description null
Width 200.0px (actual: 200px)
Height (actual: 40px)
Hide errors false
Modified false
Property read only false
Required false
Tab index 0
Caption as html false
Error message null
Immediate true
Primary style name v-filterselect
Read only false
Styles null
Enabled true
Registered event listeners null
Resources {}

I’m not sure how useful that really is but at least you can see the Immediate flag is on. RegisteredEventListeners is null, which might be relevant but, again, it only fails to work for null values. Normal values are working just fine.

Thanks for your help
Roger

Still works with buffered = false. Maybe you could just show a full example.

This is not true. The ComboBox will fire the event regardless of buffering, bufferring is only relevant for the property data source.

Okay, that behaviour of setBuffered is what I am seeing here. Yes, I agree, time for a full example. I’ll do that next.

Well I built a small example of the problem and it works perfectly. So there must be something in my code that messes it up. But at this point I don’t know what I’m looking for. The ComboBox (and it is now a ComboBox not a Select) renders fine and I can see network traffic when I open the list and select a non-null value. When I select a null value there is no network traffic. So something I am doing to that field turns off posting back to the server but only when it is null. I have to work through this and figure out what is going on but any ideas what would cause the control to behave this way?

Nope, I have no ideas. Your code should have hints in that direction :slight_smile:

I’ll let you know when I find it.

I’ve made a little bit of progress on this one. I stepped through the client code of ComboBox for a while but eventually noticed that from the working to non-working versions I have there is a difference in the web traffic.
The response to making a selection of, say, the 3rd option I see this:
request is
[[“20”, “v”, “v”, [“selected”, [“S”, [“3”]
]]]]
response is: {selected: [“3”]
, filter: “”, page: 0}
(I’ve stripped this down to the relevant parts)
On the version that doesn’t work the request is the same but the response is:
{“selected”:[“”]
,“filter”:“”,“page”:0}
The selected id is missing from the response. So I conclude that the problem is something to do with the way the server end is handling the options, ie how it attached and id to each.
Okay, there is some relevant code of mine there. I use a class I call ChoiceBase to hold the options. It holds the key, description and a Spring MessageSource to use for translation. I’m mot sure where the option id is coming from but since my ChoiceBase actually is the option I expect it is from there. Trouble is I replicated the ChoiceBase approach over to the working version, where it works fine. The other relevant code of mine is an implementation of com.vaadin.data.util.converter.Converter to convert the ChoiceBase to/from a String for display. Again, I walked that code to the working version (where it works). But there are some subtle differences between the two, I simplified the demo version slightly.
So I’m still working on this one. Feel free to make any suggestions.

Okay I have the answer, or at least an answer that works for me. In com.vaadin.ui.AbstractSelect.isSelected near the end we have this code:

            final Object value = getValue();
            return itemId.equals(value == null ? getNullSelectionItemId()
                    : value);

The return from getValue() in my case is a String, but itemId is a ChoiceBase (I mentioned that class earlier). I have registered a Converter to manage translating between String and ChoiceBase but it isn’t being used here. I also have an overidden .equals() on ChoiceBase but I had messed up the signature and it was not being used. So the solution here was to 1) fix the signature on the .equals() and 2) have it handle both String and another ChoiceBase. Once that was in place the problem went away.
Hopefully this helps someone else.