Cannot get comboboxes to work correctly in Table/TableFieldFactory

Hi all! Not sure where to put this question, so I posted it here.


In short:

The comboboxes in each field of my table in editing mode is giving me a conversion error when selecting an item, but the same logic and containers are wrking perfectly well outside of the TableFieldFactory (createField()). What am I doing wrong?


Longer explanation:

I have a container with multiple properties (columns) and items (rows). When I edit the table that is connected to this container, I want comboboxes on some of the column fields. I’m using a TableFieldFactory for that, and it is working like a charm.

I want the combobox in each field to contain the
distinct
elements from its respective property. My solution to this was to implement a method in my Container class that iterate through all properties in the container and for each property creates a new IndexedContainer with unique values from that property. The method returns a map with PropertyIds/Containers, so that I, in createField(), can pick each container from each property I want to have comboboxes for.


Example

So, say I have three propertyId’s, Foo, Bar and Baz which each “contains” several items of which some are the same, like so:


Foo

  • Chris
  • Chris
  • Meg
  • Meg
  • Meg
  • Stewie
  • Stewie

… and the same for Bar and Baz, only other values…

The getDistinctContainers() method returns a
Map
, looking like this:

[code]

Key: PropertyId: Foo
Value: Container: contains propertyId [Foo]
and the unique values of Foo, ie. [Chris, Meg, Stewie]

Key: PropertyId: Bar
Value: ... and so forth...

[/code]

When I am about to set the container datasource in createField(), the container looks like this (for property Foo):

[code]

allItemIds: [0, 1, 2]

items: {2={Foo=Stewie}, 1={Foo=Meg}, 0={Foo=Chris}}
propertyIds: [Foo]

[/code]
… which seems alright to me…

Now, the table shows the comboboxes in each field as intended. But when I click an item in a combobox, it gives me the following conversion error:

 [code]

com.vaadin.data.util.converter.Converter$ConversionException: Unable to convert value of type java.lang.Integer to model type class java.lang.String. No converter is set and the types are not compatible.
at com.vaadin.data.util.converter.ConverterUtil.convertToModel(ConverterUtil.java:181)
at com.vaadin.ui.AbstractField.convertToModel(AbstractField.java:745)
[/code]


Note:

I tried creating the same scenario outside of the table, and it worked just fine. So it seems that the comboboxes, with the same logic and the same containers, works fine outside the TableFieldFactory and the createFields() method. I can’t put my finger on why they shouldn’t work in a TableFieldFactory…


Question:


  • What do I do to get the comboboxes to set the correct values?

Here’s my Container class:

    public class SomeContainer extends IndexedContainer {
    
    	private static final long serialVersionUID = 1L;
    
    	public void addContainerProperties() {
    		addContainerProperty("Foo", String.class, null);
    		addContainerProperty("Bar", String.class, null);
    		addContainerProperty("Baz", String.class, null);
    	}
    	
    	public Map<String, Container> getDistinctContainers() {
    
    		Map<String, Container> m = new HashMap<String, Container>();
    		ArrayList<Object> filter = new ArrayList<Object>();
    
    		int id = 0;
    
    		for (Object propertyId : this.getContainerPropertyIds()) {
    
    			Container cont = new IndexedContainer();
    
    			cont.addContainerProperty(propertyId, propertyId.getClass(), null);
    
    			for (Object itemId : this.getItemIds()) {
    				Object ob = ((Item) this.getItem(itemId)).getItemProperty(propertyId).getValue();
    				if ((!filter.contains(ob.toString())) && (ob != null)) {
    					filter.add(ob.toString());
    					Item item = cont.addItem(id);
    					item.getItemProperty(propertyId).setValue(ob);
    					id++;
    				}
    			}
    			m.put(propertyId.toString(), cont);
    		}
    		return m;
    	}
    }

… and here is the relevant code for createField:

    @Override
    public Field<?> createField(Container container, Object itemId, Object propertyId, com.vaadin.ui.Component uiContext) {
    
    	TextField tField = (TextField) DefaultFieldFactory.get().createField(container, itemId, propertyId, uiContext);
    	tField.setImmediate(true);

        // ...some code here that uses the TextField
    
    	if (propertyId.equals("Foo")) {
    		ComboBox select = new ComboBox();
    		for (Map.Entry<String, Container> entry : distinctContainers.entrySet()) {
    			if (entry.getKey().equals(propertyId)) {
    				select.setContainerDataSource(entry.getValue());
    			}
    		}
			select.setImmediate(true);
			select.setItemCaptionPropertyId(propertyId);
			select.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);

    		return select;
    	}
    	// ...  if statements for Bar and Baz left out for brevity...
    	
    	return tField;
    }