Binding nested beans to table with form

Hi,

As part of our first steps in Vaadin, we’re trying to rebuild an existing user interface of one of our apps (a movie & show times database) with Vaadin.

On of the screens contains a table with cinemas. The data comes from a Cinema object that looks like this:

  • id : long
  • name : String
  • city : City
    City consists of:
  • id : long
  • name : String

Our Vaadin table has several columns to display this data, including a column for the cinema id (hidden), cinema name, the city id (hidden) and the city name (a generated column):

+---------+--------------+---------+-----------+
| id      |  cinemaname  | city id | city name |
+---------+--------------+---------+-----------+
| 123     | Cinema 1     | 1       | City A    |
| 124     | Cinema 2     | 2       | City B    |
| 125     | Cinema 3     | 1       | City A    |
:         :              :         :           :

The generated column reads the city id and looks up the corresponding city name in our database (granted, not very efficient). The reason we had to use a generated column for this follows.

We also have a form. Whenever a table row is selected, we call setItemDataSource on the form with the selected item that we get from the table, as per the Address Book example in the tutorial, so that the form is populated using the selected item’s properties. In the form, we set the generated city name' column to be hidden, and for city id’ we use a com.vaadin.ui.Select list (using a custom FormFieldFactory) that we populate with cities from our database. The itemId in the Select list is the city id, the item caption is the name.

+--------------------------------------------+
|                                            |
|  Cinema name: [ Cinema 1          ]
        |
|  City id:     [ City A         |\/]
        |
|                                            |
+--------------------------------------------+

Whenever we change the selected city in the form and commit the changes, the id is written back to the table, and the generated column shows the new name for the city, based on the (now changed) city id. Without using a generated column, the table would keep showing the old city name, as the form only changes the city id.

One issue arises: Vaadin doesn’t support sorting on a generated column, so I can’t sort on city name right now.
Is there any way around this?

More generally (and more importantly):
is this the best way to deal with “nested beans”, like our Cinema bean that contains a City bean?

It would be awesome if this would work “automatically”, e.g. if

  • you could set a bean as an item property and tell Vaadin which of the nested bean’s properties is its id and which is its display value,
  • the display value set for the bean would show up properly in the table
  • the table is sortable on the display value
  • a form based on such an item would (by default) use a Select component for its nested beans (and provide some way to set the container that populates this Select list)
  • when such a form is saved, the selected item’s id is saved into the bean being edited

I hope someone from the Vaadin team (or anyone else with a suggestion) can shed some light on this.

I would also like to hear an answer to this. We have a lot of Table type components in our app and this is driving me nuts. In JSP I can just ask for cinema.city.name.

The Tables and their Containers have been quite a burden on our project team. Listing items is quite simple with traditional techniques, but with Vaadin we’ve been working for months and still have inferior solutions to plain old paged JSP. The UI is better, but the code base is awfully complex and time consuming.

To be more exact, we have problems in two areas:

  1. Container lazy loading. We have an implementation, but it’s not generic. We need an own container class for all our domain objects. For a large app, that’s a lot of containers. And sorting doesn’t work. Sorting items in memory is not an option for large data masses, sorting has to be done on the database level.

  2. Displaying information from composite objects in a table, same problem as you.

Same thing for me : I need to sort on a generated column and it does not seem supported :frowning:
It would be great to just be able to set define a “buddy column” to a generated column so that the generated column gets sorted using its buddy’s values.

I also have this issue. I am using Vaadin with Grails. I want to access nested beans like user.address.city etc…

The BeanItemContainer and BeanContainer in Vaadin 6.6 make binding nested bean properties possible using the addNestedContainerProperty() method.

    // Create a container for beans
    final BeanItemContainer<Star> stars =
        new BeanItemContainer<Star>(Star.class);
    
    // Declare the nested properties to be used in the container
    stars.addNestedContainerProperty("equatorial.rightAscension");
    stars.addNestedContainerProperty("equatorial.declination");
    
    // Add some items
    stars.addBean(new Star("Sirius",  new EqCoord(6.75, 16.71611)));
    stars.addBean(new Star("Polaris", new EqCoord(2.52, 89.26417)));
    
    // Put them in a table
    Table table = new Table("Stars", stars);
    table.setColumnHeader("equatorial.rightAscension", "RA");
    table.setColumnHeader("equatorial.declination",    "Decl");
    table.setPageLength(table.size());
    
    // Have to set explicitly to hide the "equatorial" property
    table.setVisibleColumns(new Object[]{"name",
        "equatorial.rightAscension", "equatorial.declination"});

See
this on-line example
.

The 6.6.0.pre1 will be released shortly, but you can already use the feature in the nightly builds.
11652.png

Thanks Marko. I just tried it out and was able to add a nested property that was two levels deep (person.address.country.name) However, I still had to tell Hibernate/Grails to not use lazy loading. That is a big problem. Also, do I really need to enumerate every property using addNestedContainerProperty()? If so, it would be really helpful if you could also do addNestedContainerItem() that would add ALL the properties for that item.