ListSelect with MultiSelect does not remove deselected items

I’m using a ListSelect in a form to allow the user to select multiple objects which will be related to the main object in a one-to-many relationship. I’m working in Scala.

Let’s say I have an Appointment object and it has one or more tags assigned to it (actually, this is a many-to-many relationship). When I pull the Appointments out of the data store (I’m using an embedded key-value store), I also pull the full list of Tags. Then I use an appointment_tag bridge table to stick the appropriate tags into a Java TreeSet in the Appointment object.

I create the ListSelect and give it the Tags in a Container as its ContainerDataSource. I also set its PropertyDataSource to the set of tags associated with the Appointment (to select these in the ListSelect). This works perfectly. I get the full set of Tags in the ListSelect, and the currently associated tags are selected. Here is the code:

tags = new ListSelect()
tags.setWidth("100%")
tags.setRows(3)
tags.setMultiSelect(true)
tags.setNullSelectionAllowed(true)
tags.setContainerDataSource(tagContainer)
tags.setPropertyDataSource(appointment.getItemProperty("tags"))

Let’s say that my tags are the colors of the rainbow: red, orange, yellow, green, blue, violet. And that initially when the ListSelect is loaded, the appointment has a violet tag and “violet” is selected in the ListSelect. Now let’s assume that I de-select the violet, and select the red, green, and blue.

When I submit this form and check the ListSelect, the red, green, and blue are selected – perfect! BUT, the violet is also selected, even though it does not appear to be.

So how do I UNselect items in the ListSelect?

Thanks.

Hi Charles,

I first thought that this sounded like a bug, but ListSelect seems to work as expected in my tests. This leaves the appointment.getItemProperty(“tag”), what type is this and what happens when you change the selection in the ListSelect?

It seems like the PropertyDataSource is only updated with the added items and previously selected items are not removed from there. I tested binding an ObjectProperty as the property data source and that works just fine, so might there be that you have a custom Property implementation that misbehaves in this case? Or maby the Property is directly bound to the datastore, which doesn’t automatically purge the deselected items?

HTH,
/Jonatan

Unfortunately, I had to work around it and then moved on to other things, and I didn’t see this response until just now. I’m not sure I could even reproduce it at this point. But I will be back on that project at some point and if I can repeat the problem I’ll post a follow up here. If you couldn’t reproduce it, then it was probably something in my code. One issue is that I’m working in Scala, so sometimes there are some weird Java-Scala conversion issues (e.g. I was using a Scala collection type that worked slightly differently from the “equivalent” Java collection type).

Thanks for your response. I’ll let you know if it crops up again.

Chas.

This is definitely a bug in the ListSelect when it comes to unselecting an originally set value, but only when one was pre-selected.

My ListSelect is setRequired(true) because I want them to choose at least one item.

I have setMultiSelect(true) because I want them to be able to select more than one item.

I have setNullSelectionAllowed(false) for the same reason as required…something must be selected, there’s no default value.

I build the ListSelect and it appears just fine, pre-selecting the items in the ListSelect that match the HashSet values I give it in my PropertysetItem property defined as type java.util.Set.class. When I call setItemDataSource() using this Item, it works as expected in all ways except one.

If the Set in my Item only contains one entry because only one element is pre-selected, it behaves a bit odd.

If the ONLY thing I do in the ListSelect is CTRL-CLICK the single pre-selected/highlighted item, it appears to be unselected. But if I save, there’s no error in the isValid() check on that field (despite being required and null selection not allowed), and when I do a Form.commit() and retrieve the Set from the field’s value, the original value is still in there, hence it passed validation even though it appeared that I had unselected it and had nothing selected.

Now, if instead I click on any other item in the ListSelect first, it will no longer let me ‘unselect it’. If I CTRL-CLICK on it again, it unselects, but then re-selects it. I understand this because I’m not supposed to allow no selection. In fact, if I click on the pre-selected item first, unselect it by CTRL-CLICK, then re-select it with CTRL-CLICK, I can no longer unselect it with CTRL-CLICK, it behaves as expected, requiring at least something to be selected.

So, to me, the bug appears to be if you have a multi-select ListSelect with only one item pre-selected, if you click to unselect it (CTRL-CLICK), the UI makes it appear as though it’s not selected, but it in fact is and will remain in the field’s value set.

The best to me would be that CTRL-CLICK unselects a selected item no matter what (and never re-selects it). Then let the validation fail is nothing is selected. But based on how it seems to work now, it would also be fine if the pre-selected single item, if I CTRL-CLICK to unselect it, it should auto-reselect it like it seems to do now if you select a different item so you still only have one selected, but it’s not the pre-selected one, then try to CTRL-CLICK to unselect it (where it will re-select itself).

I can confirm that this is a bug. Created ticket
#6319
. You can observe the problem
in this on-line example
(until it’s fixed).

The problem is on the client-side: Ctrl+clicking the item doesn’t send a server request and thus doesn’t cause a value change event. The problem is not just visual as the item is really registered as unselected on the client-side so that if you Ctrl+click another item, the first item will be deselected on the server-side as well.

The required setting not working is just a byproduct. As the selection change isn’t communicated to the server, the required validation won’t know about it.

I know I’m using a nightly build of 6.5.1 (the latest dated 29th), but if someone is trying to fix this, it appears to have a bug when my multi-select ListSelect does a commit(). Whether I’ve de-selected everything, have only one or multiple selected, or not even changed, it doesn’t matter:

[font=Courier New]
com.vaadin.data.Property$ConversionException: java.lang.NoSuchMethodException: java.util.HashSet.(java.lang.String)
at com.vaadin.data.util.ObjectProperty.setValue(ObjectProperty.java:222)
at com.vaadin.ui.AbstractField.commit(AbstractField.java:241)
at com.vaadin.ui.Form.commit(Form.java:339)
at com.esignforms.open.vaadin.config.pkg.PackagePartyToDocumentPartyForm.buttonClick(PackagePartyToDocumentPartyForm.java:123)
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:490)
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:162)
at com.vaadin.ui.AbstractComponent.fireEvent(AbstractComponent.java:1166)
at com.vaadin.ui.Button.fireClick(Button.java:380)
at com.vaadin.ui.Button.changeVariables(Button.java:196)
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariableBurst(AbstractCommunicationManager.java:1294)
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariables(AbstractCommunicationManager.java:1214)
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleUidlRequest(AbstractCommunicationManager.java:730)
at com.vaadin.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:296)
at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:483)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

[/font]

Spoke too soon… Seems to happen if I revert back to 6.5.0, too. I thought it was working under 6.4.9 unless I changed something. Unfortunately, can’t prove it because I made all sorts of changes to get it to 6.5.0 that aren’t backwards compatible.

Not sure what is wrong with my code, and when debugging, I noted that AbstractSelect.getValue() for multiselect does:
[font=Courier New]

        if (retValue instanceof Set) {
            return Collections.unmodifiableSet((Set<?>) retValue);
        } else if (retValue instanceof Collection) {
            return new HashSet<Object>((Collection<?>) retValue);

[/font]

So it take my HashSet (in retValue) and creates an unmodifiableSet.

Then AbstractField.commit() does:


dataSource.setValue(newValue);

Then ObjectProperty.setValue() does:


// Gets the string constructor
final Constructor constr = getType().getConstructor(
new Class[] { String.class });

The multiselect ListSelect should allow me to use a HashSet, correct, as long as the ObjectProperty type is defined as a regular Set. So I think something broke on the Vaadin end, but if I’m doing something wrong, I’d like to fix it again.

Thanks!

Does anybody know what might have caused this problem with my multiselect ListSelect failing on Form.commit()? I just tried today’s nightly build of 6.5.1 and it still is not working. It seems to me that when my ObjectProperty’s type is Set and the actual implementation value I pass in is a HashSet, this ought to work as it did before.

The examples only show the use of arrays for setting the values. Is that a new limitation of ListSelect?

This sounds wrong because it should never get here. Instead the check

if (newValue == null || type.isAssignableFrom(newValue.getClass())) {

should be true and the value directly assigned. Unless the type of the ObjectProperty is something else than Set?

EDIT: Are you sure your ListSelect is in multiSelect mode? I tested this and had not used setMultiSelect(true) and got the same error you get, because then the value is not a Set but whatever Object you use as item id.

I found a working solution for multiselect ListSelect and ObjectProperty.

Assuming my ‘selectedValues’ is defined as a standard HashSet:

selectedValues = new HashSet();

So, the most generic way to create an object property fails because apparently it will assume the correct HashSet type, but that won’t pass isAssignableFrom as the select will return an unmodifiable collection as Set:

item.addItemProperty(“selectedValues”, new ObjectProperty(selectedValues)); // DOES NOT WORK

So, I tried to be really nice and give it all the information and thus remove the need for @SuppressWarnings(“unchecked”) too, but it also fails, still assuming it’s a HashSet, not the Set I tried to specify:

item.addItemProperty(“selectedValues”, new ObjectProperty<java.util.Set>(selectedValues)); // DOES NOT WORK

But either of the following will work, but you’ll need the @SuppressWarnings(“unchecked”):
[font=Courier New]
item.addItemProperty(“selectedValues”, new ObjectProperty(selectedValues,java.util.Set.class));

item.addItemProperty(“selectedValues”, new ObjectProperty<java.util.Set>(selectedValues,java.util.Set.class));
[/font]

What is odd is that I thought it was working before 6.5 using second form above so that I had no warnings and didn’t need to suppress anything. But maybe I somehow made that change along with the update to 6.5 since I did change code to get rid of various warnings and errors related to compatibility changes in the upgrade.

When I use a BeanItem, which uses a MethodProperty instead of ObjectProperty, this works fine as long as the bean’s get/set uses Set, and that’s the technique I mostly use. Anyway, don’t know if any of the “doesn’t work” syntax should work or not, but it seems that if ObjectProperty can’t use a HashSet type and only Set, perhaps it could handle that automatically unless there’s some other way where ObjectProperty can work with HashSet directly.

I should add that the original problem report specified in ticket #6319 is still there despite my distraction with the syntax for ObjectProperty/Set.