Table - custom content.

Hi guys,

I’ve experimented 2 ways to customize the output of a table:

  • Table.formatPropertyValue, to customize the String.
  • ColumnGenerator, to add columns with customized widget.

The tutorial shows an example of the ColumnGenerator for e-mail addresses links:
http://vaadin.com/tutorial/-/page/tuning.html#tuning.addresses

It’s crystal clear to me.

In the tutorial, they retrieve the Person bean to get the mail (p.getEmail()):

    // customize email column to have mailto: links using column generator
         addGeneratedColumn("email", new ColumnGenerator() {
             public Component generateCell(Table source, Object itemId,
                     Object columnId) {
                 Person p = (Person) itemId;
                 Link l = new Link();
                 l.setResource(new ExternalResource("mailto:" + p.getEmail()));
                 l.setCaption(p.getEmail());
                 return l;
             }
         });

What if the column you wanna decorate is already defined as a column of the table.
Here is an example, where the bean is not in the data source (contrary to the tutorial).


		table.addContainerProperty("FirstName", String.class, null);
		table.addContainerProperty("e-mail", Date.class, null);

		for (Person p : PersonList) {
			Object[] rowValues = new Object[]
 {
			    	p.getFirstName(),
			    	p.getEmail()
			    };
		    table.addItem(rowValues, p.getId());  // getId returns the DB primary key (a Long).
		}

In this example, we would like to override a method similar to Table.formatPropertyValue, but to customize the Component (not only the String), so we can return a Link for the “e-mail” column.
We could not create a ColumnGenerator for the “e-mail” column, because the column name already exists (and it better exist, else, we don’t have access to the e-mail data from the table).

The different in the tutorial is that the ColumnGeneator has access to the bean (p.getEmail()) which is stored in the Table.
In my example, the bean is not stored in the table.

Question: is there a way to make the e-mail appear as a link in my example (where the bean is not stored in the table → hard to get in the ColumnGenetor class) ?

Hope this is clear.
Thank you.

John.

You could add “generatedEmail” with ColumnGenerator that generates Links from “email” column, but hide email column from UI with setVisibleColumns.

Thank you for your reply.

I had the same idea, but I’m new to the framework and it’s great to have real-world advices from veterans.
I tried and it worked fine.

There is one little problem.

I use the Table.addItem method, and it’s Javadoc says:

 Adds the new row to table and fill the visible cells (except generated
     * columns) with given values.

And I need to give a value to the hidden column…


		table.addContainerProperty("FirstName", String.class, null);
		table.addContainerProperty("e-mailData", String.class, null);
		table.addGeneratedColumn("e-mail", new ColumnGenerator() {
			@Override
			public Component generateCell(Table table, Object itemId, Object columnId) {
				Property prop = table.getItem(itemId).getItemProperty("e-mailData");
				String email = (String)prop.getValue();
				Link link = new Link(email, new ExternalResource("mailto:"email)); 
				return link;
			}
		});

		table.setVisibleColumns(new String[]{"FirstName", "e-mail"});

		for (Person p : PersonList) {
			Object[] rowValues = new Object[]
 {
			    	p.getFirstName(),
			    	p.getEmail()
			    };
		    table.addItem(rowValues, p.getId());  // getId returns the DB primary key (a Long).
		}

As a result, my table looks empty.

I’ve to move table.setVisibleColumns at the end, when my data is in the table.
The problem is that I re-fill my table with other data according to some user action.
I’ve probably to create a new Table instance each time. Any better idea is welcome.

Have a look at the inherited addItem methods from AbstractSelect. You can do e.g.

Item item = table.addItem(p.getId());

The returned item can be used to set (or change) any property, for example:

item.getItemProperty("FirstName").setValue("Somebody");
item.getItemProperty("e-mailData").setValue("me@somewhere.com");

Hi guys,

I might have missed something here, but couldn’t you achieve the links by doing something like this:

table.addContainerProperty("FirstName", String.class, null);
table.addContainerProperty("e-mail", Link.class, null);
 
for (Person p : PersonList) {
  Link emailLink = new Link();
  emailLink.setResource(new ExternalResource("mailto:" + p.getEmail()));
  emailLink.setCaption(p.getEmail());
  Object[] rowValues = new Object[]
 {
      p.getFirstName(),
      emailLink
    };
  table.addItem(rowValues, p.getId());  // getId returns the DB primary key (a Long).
}

Note that the e-mail property is a Link.class and we just add the emailLink to the rowValues instead of the email string.

Or I just misunderstood what you’re searching for :slight_smile:
/Jonatan

Thank you Artur and Jonatan,

Both of your solutions demonstrates the beauty for this framework again.
I’ll take Jonatan solution: just fill the table with widgets :bashful::grin: