How to use Table control in Apache Click

561 views Asked by At

I would like to know how to use the Table control in Apache Click. What I really need to know is how to populate a Table control. The examples I have seen so far involve the use of methods that are not defined in the example. In the example below, the methods getCustomerService() and getCustomersSortedByName(10) are not defined, making this example difficult to follow. Would anyone know of a simple way to populate a Table control? A complete example would be great.

public class SimpleTablePage extends Page {
    @Bindable protected Table table = new Table();

    // Constructor ------------------------------------------------------------
    public SimpleTablePage() { 
        table.setClass(Table.CLASS_ITS);
        table.addColumn(new Column("id"));
        table.addColumn(new Column("name"));            
        table.addColumn(new Column("email"));
        table.addColumn(new Column("investments"));
    }

    // Event Handlers ---------------------------------------------------------
    /** * @see Page#onRender() */
    @Override
    public void onRender() { 
        List list = getCustomerService().getCustomersSortedByName(10); 
        table.setRowList(list);
    }
}
1

There are 1 answers

1
Steven On

I realize this question is months old, but it doesn't have any answers and I feel it deserves one.

I was disappointed by this example as well. There's no indication to what the list should be. I don't remember how I found this answer. Maybe by staring at the Table's code for too long. The actual rendering of the data is located in the Column class's render method.

The List that should be passed to the Table in the setRowList function should be a List<Map<String,Object>>. Each Map represents a single row with the Map being keyed on the table's column names. The contents of that row's cells will be the result of the Maps' value's toString() method.

private List<Map<String,Object>> getCustomersSortedByName( final int count )
{
    final List<Map<String,Object>> toReturn = new LinkedList<Map<String,Object>>();
    //I call all my return variables "toReturn" so I know what's going to come out.

    final Customer customers[count];

    //populate your customer array and sort it here

    for( final Customer customer : customers )
    {
        final Map<String,Object> customerMap = new HashMap<String,Object>();
        customer.put( "id", customer.getId() );
        customer.put( "name", customer.getName() );
        customer.put( "email", customer.getEmail() );
        customer.put( "investments", customer.getInvestments() );

        toReturn.add( customerMap );
    }

    return toReturn;
}

That's not cut-and-paste code and might create errors. It's still a demonstration of Table.setRowList(List).

There's also the Table.setDataProvider(DataProvider) method, but it seems to me to be a longer way to do what setRowList already does. DataProvider wants an iterator that returns a Map<String,Object> too. I haven't found an advantage to using this method yet, but I have used it in an example code.

public TestPage extends Page
{
    private Table table = new Table( "table" );

    @Override
    public void onInit()
    {
        table.addColumn( new Column( "property", "property" ) );
        table.addColumn( new Column( "value", "value" ) );
        table.setDataProvider( new DataProvider(){
                                                  public List getData(){
                                                          return someList();
                                                  }
                                                  } );
        addControl( table );
    }

    private List<Map<String,String>> someList()
    {
        final List<Map<String,String>> toReturn = new LinkedList<Map<String,String>>();
        final Enumeration e = System.getProperties().propertyNames();
        while( e.hasMoreElements() )
        {
            final String prop = (String) e.nextElement();
            final Map<String,String> property = new TreeMap<String,String>();
            property.put( "property", prop );
            property.put( "value", System.getProperty( prop, "N/A" ) );
            toReturn.add( property );
        }
        return toReturn;
    }
}

This was just proof-of-concept code written yesterday so I didn't bother cleaning it. I'm not sure what the advantage is here since the time it takes to render all this is the same regardless of which method you use. With this method, data processing takes place at rendering rather than initialization. Seems like this is a lazy-initializer pattern as nothing is done with the data until rendering.