Reputation: 3225
I've been creating tables by adding a ListView
(providing it with my data as a List<MyObject>
) to the page, and assigning the corresponding ids to each column in the html file.
However now I have a situation where instead of a simple List<MyObject>
I have List<Map<String,MyObject>>
. I also get a list with all the possible keys of the nested map (List<String>
). Now I need to create a table where each value of the Map
should be in the column with the name of the key pointing to that value.
Let's say I have the following data:
keys = ['a', 'b']
data = [ { 'a' = 1, 'b' = 2 },
{ 'a' = 3, 'b' = 4 },
{ 'a' = 5, 'b' = 6}]
I would like to create the table:
<table>
<tr>
<th>a</th>
<th>b</th>
</tr>
<tr>
<td>1</td>
<td>2</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>5</td>
<td>6</td>
</tr>
</table>
Knowing that the names and number of keys in the nested Map can change, what is the best way to implement this in wicket?
Upvotes: 3
Views: 12703
Reputation: 476
Thanks Tetsuo! I've filled in the Generics for Tetsuo's variable column examples:
Wicket HTML
<html xmlns:wicket="http://wicket.apache.org">
<body>
<h3>Example 1</h3>
<table wicket:id="dataTable"></table>
<br>
<h3>Example 2</h3>
<table>
<tr>
<th wicket:id="headers">
<span wicket:id="header"></span>
</th>
</tr>
<tr wicket:id="listView">
<td wicket:id="nested">
<span wicket:id="value"></span>
</td>
</tr>
</table>
</body>
</html>
Wicket Java
public class HomePage extends WebPage
{
/** Represents serialVersionUID. */
private static final long serialVersionUID = 20150701L;
static final String A = "alpha";
static final String B = "beta";
static final String C = "gamma";
public HomePage()
{
super();
final List<String> keys = Arrays.asList(A, B, C);
final List<Map<String,Integer>> data = Arrays.asList
(
map(A, 1).put(B, 11).put(C, 21).toMap(),
map(A, 2).put(B, 12).put(C, 22).toMap(),
map(A, 3).put(B, 13).put(C, 23).toMap(),
map(A, 4).put(B, 14).put(C, 24).toMap(),
map(A, 5).put(B, 15).put(C, 25).toMap(),
map(A, 6).put(B, 16).put(C, 26).toMap(),
map(A, 7).put(B, 17).put(C, 27).toMap(),
map(A, 8).put(B, 18).put(C, 28).toMap(),
map(A, 9).put(B, 19).put(C, 29).toMap()
);
// Using a DefaultDataTable
ISortableDataProvider<Map<String,Integer>,String> dataProvider =
new SortableDataProvider<Map<String,Integer>,String>()
{
/** Represents serialVersionUID. */
private static final long serialVersionUID = HomePage.serialVersionUID;
public Iterator<Map<String,Integer>> iterator(long first, long count)
{
int start = Math.max(0, (int) first);
int end = Math.min(data.size(), start + (int) count);
return data.subList(start, end).iterator();
}
public long size()
{
return data.size();
}
public IModel<Map<String,Integer>> model(Map<String,Integer> object)
{
return new CompoundPropertyModel<Map<String,Integer>>(object);
}
};
List<PropertyColumn<Map<String,Integer>,String>> columns =
new ArrayList<PropertyColumn<Map<String,Integer>,String>>();
for (String key : keys)
columns.add(new PropertyColumn<Map<String,Integer>,String>(Model.of(key), key));
// Example 1 - Using a DataTable
// Wicket: "dataTable"
add(new DefaultDataTable<Map<String,Integer>,String>("dataTable", columns, dataProvider, 5));
// Example 2 - Using nested ListViews
// Wicket: "headers"
add
(
new ListView<String>("headers", keys)
{
/** Represents serialVersionUID. */
private static final long serialVersionUID = HomePage.serialVersionUID;
@Override
protected void populateItem(ListItem<String> item)
{
// Wicket: "header"
item.add(new Label("header", String.valueOf(item.getModelObject())));
}
}
);
add
(
// Wicket: "listView"
new ListView<Map<String,Integer>>("listView", data)
{
/** Represents serialVersionUID. */
private static final long serialVersionUID = HomePage.serialVersionUID;
@Override
protected void populateItem(ListItem<Map<String,Integer>> item)
{
final Map<String,Integer> rowMap = item.getModelObject();
item.add
(
// Wicket: "nested"
new ListView<String>("nested", keys)
{
private static final long serialVersionUID = HomePage.serialVersionUID;
@Override
protected void populateItem(ListItem<String> item)
{
Integer value = rowMap.get(item.getModelObject());
// Wicket: "value"
item.add(new Label("value", String.valueOf(value)));
}
}
);
}
}
);
}
// Make building the data structure a little more fun :)
private MapBuilder<String, Integer> map(String key, Integer value)
{
return new MapBuilder<String, Integer>().put(key, value);
}
private static class MapBuilder<K, V>
{
Map<K, V> map = new HashMap<K, V>();
MapBuilder<K, V> put(K key, V value)
{
map.put(key, value);
return this;
}
Map<K, V> toMap()
{
return map;
}
}
}
Generic Usage
DefaultDataTable extends DataTable
IColumn
ISortableDataProvider
Upvotes: 1
Reputation: 6334
You can nest ListView
. The markup you want will look something like this:
<table>
<tr><th wicket:id="headerlist"><span wicket:id="header"></span></th></tr>
<tr wicket:id="contentlist"><td wicket:id="column">
<span wicket:id="data"></span>
</td></tr>
</table>
You will then need three ListView
. The first (headerlist
) will fill in the headers from the keys
list. This is simple, so I'll skip the example.
The second (contentlist
) will be across your data
list. In the populateItems
method you will add the third ListView
(column
), which will again iterate across the keys
list:
add(new ListView<Map<String,MyObject>>("contentlist", data) {
protected void populateItem(ListItem<Map<String,MyObject>> item) {
final Map<String,MyObject> map = item.getModelObject();
// Inner list - using item.add to add to the inner list
item.add(new ListView<String>("column", keys) {
protected void populateItem(ListItem<String> item) {
String key = item.getModelObject();
item.add(new Label("data", map.get(key).toString()));
}
});
}
});
Upvotes: 7
Reputation: 10896
Below, examples using DefaultDataTable and nested ListViews.
Note that, while the DataTable approach may look less straightforward (well, it depends on the eye of the beholder), it actually separates more cleanly data fetching from visualization, and you get pagination out-of-the-box: try adding more data, or lowering the rowsPerPage
(DefaultDataTable's last constructor param).
public class HomePage extends WebPage {
static final String A = "a";
static final String B = "b";
public HomePage() {
final List<String> keys = Arrays.asList(A, B);
final List<Map<String, Integer>> data = Arrays.asList(
map(A, 1).put(B, 11).toMap(),
map(A, 2).put(B, 12).toMap(),
map(A, 3).put(B, 13).toMap(),
map(A, 4).put(B, 14).toMap(),
map(A, 5).put(B, 15).toMap(),
map(A, 6).put(B, 16).toMap(),
map(A, 7).put(B, 17).toMap(),
map(A, 8).put(B, 18).toMap(),
map(A, 9).put(B, 19).toMap());
// Using a DefaultDataTable
ISortableDataProvider dataProvider = new SortableDataProvider() {
public Iterator iterator(int first, int count) {
int start = Math.min(0, first);
int end = Math.min(data.size(), start + count);
return data.subList(start, end).iterator();
}
public int size() {
return data.size();
}
public IModel model(Object object) {
return new CompoundPropertyModel(object);
}
};
List columns = new ArrayList();
for (String key : keys)
columns.add(new PropertyColumn(Model.of(key), key));
add(new DefaultDataTable("dataTable", columns, dataProvider, 20));
// Using a nested ListViews
add(new ListView("headers", keys) {
@Override
protected void populateItem(ListItem item) {
item.add(new Label("header", String.valueOf(item.getModelObject())));
}
});
add(new ListView("listView", data) {
@Override
protected void populateItem(ListItem item) {
final Map rowMap = (Map) item.getModelObject();
item.add(new ListView("nested", keys) {
@Override
protected void populateItem(ListItem item) {
Object value = rowMap.get(item.getModelObject());
item.add(new Label("value", String.valueOf(value)));
}
});
}
});
}
// to make building the data structure a little more fun :)
private MapBuilder<String, Integer> map(String key, Integer value) {
return new MapBuilder<String, Integer>().put(key, value);
}
private static class MapBuilder<K, V> {
Map<K, V> map = new HashMap<K, V>();
MapBuilder<K, V> put(K key, V value) {
map.put(key, value);
return this;
}
Map<K, V> toMap() {
return map;
}
}
}
<html xmlns:wicket="http://wicket.apache.org">
<body>
<table wicket:id="dataTable"></table>
<table>
<tr>
<th wicket:id="headers">
<span wicket:id="header"></span>
</th>
</tr>
<tr wicket:id="listView">
<td wicket:id="nested">
<span wicket:id="value"></span>
</td>
</tr>
</table>
</body>
</html>
Upvotes: 9