Table, Container and related Objects

Hello guys.

Even it seems to be trivial, I couldn’t find an answer for my question yet.

Using Hibernate I’ve stored some related objects in the database. Now I want to display these in a table. Of course, fields with related objects cannot be displayed instantly.

Let’s give an example.

class Mother {
  private String name = "Lisa";
  public static Mother get() {
    return new Mother();
  }
}

class Child {
  private String name = "Peter";
  private Mother mother = Mother.get();
}

When I want to list all childs in a table, with the mother displayed as “Lisa” how do I do that?

Thanks for answering

So you want a table with the columns ‘mother’ and ‘child’ (or ‘name’ or what ever you want to call it)?

Tables doesn’t care where the data comes from. You can pick and choose from multiple spots and just combine it. In fact it this is the specifications of a container, but all the alot of the API calls in the table are just wrapper methods for the container methods. A table has a IndexedContainer by default

Here’s how to build up the table, with my interpretation of the specifications:


// Set up the table
Table table = new Table("My Fine Table");

// Give the table the columns you want
// The parameters are indentifier, data type and default value
container.addContainerProperty("Mom", String.class, "");
container.addContainerProperty("Child", String.class, "");

// Loop through every child and put the data into the table
// I suppose you have a collection of every child, 
// and I called that collection children.
for(Child child : children){
  // Create a new item to the table with the child as row id
  Item item = table.addItem(child);
  // insert the names of the child and mother into the row
  // as you can see, i've added two getters to the child class
  // so that I can get the names easily
  item.getItemProperty("Mom").setValue(child.getMother());
  item.getItemProperty("Child").setValue(child.getName());
}


// This is all you need. Next code is not needed, and it will
// just demostrate that you can add anything to a table that
// just complies with the column specifications
Item item = table.addItem("foo");
item.getItemProperty("Mom").setValue("bar");
item.getItemProperty("Child").setValue("baz");

The code started to look quite long but it’s just because there is more comments than code. :lol: I didn’t test the code so there might be some bugs.

Thank you, that looks like what I want. But it doesn’t work as expected. I build the child-mother example. A list of children should be displayed, with a column “mother”.

package com.itmill.toolkit.test;

public class Child {

  private String name;
  private Mother mother;
  
  public Child() {
    
  }

  public Child( String name, Mother mother ) {
    this.name = name;
    this.mother = mother;
  }

  // + Getters and setters
}
package com.itmill.toolkit.test;

import com.itmill.toolkit.data.util.BeanItemContainer;

public class ChildContainer extends BeanItemContainer<Child> {

  public ChildContainer() throws InstantiationException, IllegalAccessException {
    super( Child.class );
  }
}
package com.itmill.toolkit.test;

public class Mother {

  private String name;

  public Mother( String name ) {
    this.name = name;
  }

  // + Getters and setters
}
package com.itmill.toolkit.test;

import com.itmill.toolkit.Application;
import com.itmill.toolkit.data.Item;
import com.itmill.toolkit.ui.Table;
import com.itmill.toolkit.ui.Window;

public class Launcher extends Application {

  @Override
  public void init() {
    addWindow( new Window() );

    Table table = new Table( "ChildTable" );
    table.addContainerProperty( "child", String.class, "" );
    table.addContainerProperty( "mother", String.class, "" );
    table.setSizeFull();
    
    ChildContainer container;
    
    try {
      
      container = new ChildContainer();
      /* Using the following two lines causes an UnsupportedOperationException */
//      container.addContainerProperty( "child", String.class, "" );
//      container.addContainerProperty( "mother", String.class, "" );
      
      table.setContainerDataSource( container );
      
      Child child = new Child( "Peter", new Mother( "Lisa" ) );
      
      Item item = container.addItem( child );

      /*
       * It doesn't matter what I set the value to.
       * The mother's value is still
       * "com.itmill.toolkit.test.Mother@1e4f7c2"
       */
      item.getItemProperty( "mother" ).setValue( child.getMother().getName() );
//      item.getItemProperty( "mother" ).setValue( "foo" );
      
    } catch ( InstantiationException e ) {
      e.printStackTrace();
    } catch ( IllegalAccessException e ) {
      e.printStackTrace();
    }
    
    getMainWindow().addComponent( table );
  }
}

What also confuses me is that item.getItemProperty(“mother”) returns the Mother instance instead of a Property object. It seems like a bug, as behavior for item.getProperty(“mother”).getValue() also returns the mother object.

Whats wrong?

ah, so you are using a BeanItemContainer (BIC from now on), instead of a IndexedContainer.

I don’t remeber directly exactly how the BIC works, but if I recall correctly, it shows directly what is inside the object. For example, if you have your BIC for child objects, the container will get the columns String name and Mother mother, and you can’t change these. You can however hide some columns and reorder them.

This is why you always get the Mother object to the table, as Child contains a Mother field. This is also why you get exceptions when you try to change the fields of the container, as it is not allowed. BIC is to make it fast and simple to just show a collection of object of the same type. You don’t need to define the properties or fill the values with getItemProperty().setValue().

The easiest way to fix what you are doing would to remove all addContainerProperty() and getProperty().setValue() and give the Mother class a toString that just returns the name, eg. public String toString(){return getName();}. This is however not very neat (using toString to show something in the UI). You will still get the mother object with getContainerProperty(“mother”).getValue(); but the table will use the toString to represent it in the table.

To get more control over what you are doing, you’d have to change the BIC into a IndexedContainer. “De-commenting” the addContainerProperties should then get you pretty close to what you are trying to do.

Good luck! :slight_smile:

Thank you guy, you’re great :smiley:

Here’s the working example for anyone who has a smiliar problem.

package com.itmill.toolkit.test;

public class Child {

  private String name;
  private Mother mother;
  
  public Child() {
    
  }

  public Child( String name, Mother mother ) {
    this.name = name;
    this.mother = mother;
  }

  public String getName() {
    return name;
  }

  public Mother getMother() {
    return mother;
  }
}
package com.itmill.toolkit.test;

import com.itmill.toolkit.data.util.IndexedContainer;

public class ChildContainer extends IndexedContainer {

  public ChildContainer() {
    
  }
}
package com.itmill.toolkit.test;

public class Mother {

  private String name;

  public Mother( String name ) {
    this.name = name;
  }

  public String getName() {
    return name;
  }
}
package com.itmill.toolkit.test;

import com.itmill.toolkit.Application;
import com.itmill.toolkit.data.Item;
import com.itmill.toolkit.ui.Table;
import com.itmill.toolkit.ui.Window;

public class MotherChildExample extends Application {

  @Override
  public void init() {
    addWindow( new Window() );
    Table table = new Table( "ChildTable" );
    table.setSizeFull();

    ChildContainer container = new ChildContainer();
    container.addContainerProperty( "mother", String.class, "" );
    container.addContainerProperty( "child", String.class, "" );
    
    table.setContainerDataSource( container );

    Child child = new Child( "Peter", new Mother( "Lisa" ) );

    Item item = container.addItem( child );
    item.getItemProperty( "mother" ).setValue( child.getMother().getName() );
    item.getItemProperty( "child" ).setValue( child.getName() );
    
    getMainWindow().addComponent( table );
  }
}