Databinding problem

Hi, I want to create a plain and simple “table-edit” form, i.e. a table with a list of beans on top, and below an edit form where the user can edit the bean he selected in the table.

For the data binding in the edit form, I want to use the fieldgroup-mechanism. The code for the edit form looks something like this (the sample bean has two fields, “id” and “name”):

public class EditForm extends CustomComponent {

    private VerticalLayout formLayout;
    private FieldGroup fieldGroup;

    // fields "id" and "name"
    @PropertyId("id")
    private TextField idTextField;
    
    @PropertyId("name")
    private TextField nameTextField;

    [...]

    //creating fields
    nameTextField = new TextField();
    idTextField = new TextField();   
    formLayout.addComponent(idTextField);
    formLayout.addComponent(nameTextField);
   
   //bind fields
   fieldGroup = new FieldGroup();
   fieldGroup.bindMemberFields(this);
  
   [...]

  
   //loading new bean
   public void setBean(Bean bean) {
        fieldGroup.setItemDataSource(new BeanItem(bean));
   }
}

Now initially everything works fine, table and edit form are being displayed. The problem is when the user clicks a line in the table, the edit form isn’t updated with the selected bean. At the table, I registered a valueChangeListener which calls the “setBean(…)” method above, and this is being executed. However, although I do change the fieldgroup’s datasource to the new selected bean, the textfields in the UI simply don’t update. I noticed that only when setting the fieldGroup’s datasource immediately during creation of the edit form (e.g. directly after creating the textfields), the textfields are being filled with the bean’s values.

Any help would be very much appreciated!

Not sure how you implemented the valuechangelistener, however the address book tutorial (
https://vaadin.com/tutorial
) does not seem to create a new Bean to bind form items to table.

contactList.addValueChangeListener(new Property.ValueChangeListener() {
    public void valueChange(ValueChangeEvent event) {
        Object contactId = contactList.getValue();
        editorFields.setItemDataSource(contactList.getItem(contactId));
        editorLayout.setVisible(contactId != null);
    }
});

Using fieldGroup.bind(…) may be helpful as below example.

public class TestComponent extends CustomComponent {
    
//    @PropertyId("id")
    private TextField idTextField;
//    @PropertyId("name")
    private TextField nameTextField;
    private FieldGroup fieldGroup;

    public TestComponent() {
        FormLayout formLayout = new FormLayout();
        this.setCompositionRoot(formLayout);
        idTextField = new TextField("Id");
        formLayout.addComponent(idTextField);
        nameTextField = new TextField("Name");
        formLayout.addComponent(nameTextField);
        
        fieldGroup = new FieldGroup();
//        fieldGroup.bindMemberFields(this);
        fieldGroup.bind(idTextField, "id");
        fieldGroup.bind(nameTextField, "name");
        
    }
    
    public void setDataSource(Student student){
        fieldGroup.setItemDataSource(new BeanItem<Student>(student));
    }
}

Thank you for your answers, Oscar and gon gon. I tried both of your suggestions but with no success.

The valueChangeListener works fine, and it calls the setBean(…) method with the selected bean. I changed it to pass the entire BeanItem, as in the tutorial example, but it doesn’t help.

I found out that even setting a textfield invisible in the setBean(…) method has no effect. So it seems there’s something wrong with the update of the UI itself. Strangely, I can set the whole EditForm invisible there, but not a textfield within. Maybe this rings some solution with you.

i found that if want to use @PropertyId, the FieldGroup contructor must have a BeanItem as a parameter e.g.

    fieldGroup = new FieldGroup(new BeanItem<Bean>(bean));

the below example is tested with ok.

public class TestComponent extends CustomComponent {
    
    @PropertyId("id")
    private TextField idTextField;
    @PropertyId("name")
    private TextField nameTextField;
    private FieldGroup fieldGroup;

    public TestComponent(Bean bean) {
        FormLayout formLayout = new FormLayout();
        this.setCompositionRoot(formLayout);
        idTextField = new TextField("Id");
        formLayout.addComponent(idTextField);
        nameTextField = new TextField("Name");
        formLayout.addComponent(nameTextField);
        
        fieldGroup = new FieldGroup(new BeanItem<Bean>(bean));
        fieldGroup.bindMemberFields(this);
        
    }
    
    public void setBean(Bean bean){
        System.out.println("test bean");
        fieldGroup.setItemDataSource(new BeanItem<Bean>(bean));
    }