Databinding with ListSelect (only show binded values)

Hi,

I am using Vaadin 7 and I am trying to bind a list of items to a ListSelect using FieldGroup. The current behavior is that the ListSelect needs to be populated upfront will all available items and that the binding will only highlight/select the items from the binding object.

In one way this is sort of logical but in my case I want to start with an empty list and ONLY show the binded items. So instead of a ListSelect containing:

  • Item 1
  • Item 2 (selected)
  • Item 3
  • Item 4
  • Item 5 (selected)

I want a ListSelect containing only the binded items:

  • Item 2
  • Item 5

Is this possible with Vaadin?

Here is some code I used to test the binding data with the ListSelect:


public class MyVaadinUI extends UI
{

    @PropertyId("orderNumber")
    TextField descriptionField = new TextField("Order number");

    @PropertyId("products")
    ListSelect productsField = new ListSelect("Products");

    private Set<Product> allProducts = Sets.newHashSet();
    private BeanFieldGroup<Order> fieldGroup = new BeanFieldGroup<Order>(Order.class);
    
    @Override
    protected void init(VaadinRequest request) {
        final VerticalLayout layout = new VerticalLayout();
        layout.setMargin(true);
        layout.setSpacing(true);
        setContent(layout);

        // create a list with all products
        createProducts();
        
        productsField.setMultiSelect(true);
        productsField.setItemCaptionMode(ItemCaptionMode.PROPERTY);
        productsField.setItemCaptionPropertyId("productName");
        layout.addComponent(productsField);
        
        // wrap list with all products in bean container and add it to the listselect
        productsField.setContainerDataSource(createProductsDataSource());
        layout.addComponent(descriptionField);


        // binding the data
        Order order = createOrder();
        fieldGroup.setItemDataSource(new BeanItem<Order>(order));
        fieldGroup.bindMemberFields(this);
    }
    
    // create random products
    private void createProducts() {
        for (int i = 0; i < 10; i++) {
            allProducts.add(new Product("Product #" + i, i));
        }
    }

    // creates bean container that contains allProducts
    private BeanItemContainer<Product> createProductsDataSource() {
        BeanItemContainer<Product> container = new BeanItemContainer<Product>(Product.class);
        container.addAll(allProducts);
        return container;
    }

    // create order with 5 products out of the available allProducts
    private Order createOrder(){
        Set<Product> orderProducts = Sets.newHashSet();
        Iterator<Product> iterator = allProducts.iterator();
        for (int i = 0; i < 5; i++){
            orderProducts.add(iterator.next());
        }

        return new Order("My Order", orderProducts);
    }

    public class Order {

        private String orderNumber;
        private Set<Product> products;

        public Order(String orderNumber, Set<Product> products) {
            this.orderNumber = orderNumber;
            this.products = products;
        }

        public final String getOrderNumber() {
            return orderNumber;
        }

        public final void setOrderNumber(String orderNumber) {
            this.orderNumber = orderNumber;
        }

        public final Set<Product> getProducts() {
            return products;
        }

        public final void setProducts(Set<Product> products) {
            this.products = products;
        }
    }
    
    public class Product {

        private String productName;
        private Integer quantity;

        public Product(String productName, int quantity) {
            this.productName = productName;
            this.quantity = quantity;
        }

        public final String getProductName() {
            return productName;
        }

        public final void setProductName(String productName) {
            this.productName = productName;
        }

        public final int getQuantity() {
            return quantity;
        }

        public final void setQuantity(int quantity) {
            this.quantity = quantity;
        }
    }
}

Not really at least as any straight forward method. ListSelect shows its items based on the ContainerDataSource the bound PropertySource is the selection (as you already noticed). You need to alter the given Container to see ListSelect to update its item set.

You could try the com.vaadin.ui.TwinColSelect and hide the Left side ListBox and the controll buttons with CSS.
But be warned, this is a nasty hack, and you will need to get creative with the CSS to make the component display as intended.