Table: updating dependent select on value change

Hi all,

I’m quite new to vaadin. It is still very impressive to me as everyting seems quite easy and the documentation and forum are on a high level.

Now I came up with a - I thought - quite common requirement. I want to edit a set of entries in an table. There are several Select fields in the table, two of them being dependent of another. So if Select A’s value is changed the contents of Select B have to be updated.

I didn’t find a way to do it with pure vaadin but I had to do some extensions to my classes I thought the framework should provide. This is a short summary of what I did:

  1. In my TableFieldFactory implementation I added a two-dimensional cache for caching the field instances created in createField so I could access the fields with the objectId and propertyId available in the valueChange method.
  2. I extended the Select class to provide easy access to the entity edited (i.e. the data in the table row ).
  3. In the valueChange method I access the select, taking the entity provided and access the select(s) to update by using the entity and the column name.

[font=Courier New]

public void valueChange(Property.ValueChangeEvent event) {
Field field = (Field) event.getProperty();
if (field instanceof ExtendedSelect) {
ExtendedSelect select = (ExtendedSelect) field;
Entry entry = select.getEntry();
Object value = field.getValue();
if (value instanceof Project) {
Project project = (Project) value;
updateContainerForSelect(entry, project);
}
}
}

private void updateContainerForSelect(Entry entry, Project newProject) {
Select select = (Select) oneDayTable.getField(entry, RecordingFields.WORK_PACKAGE);
if (select != null) {
BeanItemContainer workPackageContainer =
oneDayTable.getOneDayTableFieldFactory().createWorkPackageContainer(newProject);
select.removeAllItems();
select.setContainerDataSource(workPackageContainer);
}
}

[/font]

As this requires a lot of manual work I just wanted to know if there is a more convenient way to achieve this.

Best regards,

Stefan.

Would
this example
help?

Table rows are bound to items in the Vaadin data model, which are also used in Form, so the case should be similar.

Thanks for the fast reply.

The table could indeed be accessed via the uiContect parameter, but I haven’t seen a way to retrieve the field for a given rowId and columnId - maybe I missed it in the docs. I’ll give it a try and post my results.

Thanks so far.

This is what I have now after adapting the example’s suggestions, an snippet from my TableFieldFactory where the first select is created updating the second select on value-change.


  selectProject.addListener(new Property.ValueChangeListener() {

    @Override
    public void valueChange(Property.ValueChangeEvent event) {
      Select workPackageSelect = (Select) getField(entry, RecordingFields.WORK_PACKAGE.getKey());
      if (workPackageSelect != null) {
        Field field = (Field) event.getProperty();
        Object value = field.getValue();
        if (value != null && value instanceof Project) {
          Project newProject = (Project) value;
          BeanItemContainer<WorkPackage> workPackageContainer =
              createWorkPackageContainer(newProject);
          workPackageSelect.removeAllItems();
          workPackageSelect.setContainerDataSource(workPackageContainer);
        }
      }
    }
  });

I still don’t see a way to access the field (first line in the valueChange method) other than to use a cache (which is accessed in the getField method. The uiContext is a Table instance, but when I retrieve table.getItem(entry) I get a MethodProperty instance.

Anyway, this is at least a more convenient way to fulfill my requirements.

Thanks again,

Stefan.

You might want to take a look of another thread here:
http://vaadin.com/forum/-/message_boards/view_message/461927
.

Table does not keep a map from individual row and column identifiers to the components generated using the field factory in getPropertyValue(). Therefore, you need to somehow keep track of the components yourself with a cache unless you the values in the container are the components themselves (often not convenient, but in this case you would not need any field factory).