How to iterate Map <String, Collection> into datatable in f
Using JSF 2.1 for Purposes
class FOO{
String name;
String value;
public void setName(String name){
this.name=name;
}
public String getName(){
return this.name;
}
public void setValue(String value){
this.value=value;
}
public String getValue(){
return this.value;
}
}
I have Map<String, List<FOO>>
The title name must be the Map Key. I need to create multiple columns (i.e. map size) and each column needs to have a FOO list in order to display FOO.Name in rows.
Example: if the map size is 4
Coulmns ----- Key1
1st column List<FOO>
ROWs versus Key1
Coulmns ----- Key2
1st column List<FOO>
ROWs versus Key2
Coulmns ----- Key3
1st column List<FOO>
ROWs versus Key3
Coulmns ----- Key4
1st column List<FOO>
ROWs versus Key4
Can anyone tell me which component to use to display this type of output in the xhtml page? I tried to use dynamic data creation but couldn't show it.
source to share
You have the wrong data structure. Change it to the correct data structure. The easiest way is to collect the data into List<Map<String, Object>>
which the property represents rows
. Map
represents columns keyed by column name. Collect the names of these columns in a separate List<String>
one that represents the property columns
. Finally, show it like this <p:columns>
:
<p:dataTable value="#{bean.rows}" var="row">
<p:columns value="#{bean.columns}" var="column">
#{row[column]}
</p:columns>
</p:dataTable>
Here's how you can convert the weird data structure to the data structure you want, if necessary (and assuming that each List<FOO>
is the same size, the whole data structure makes it less understandable otherwise):
Map<String, List<FOO>> wrongDataStructure = createItSomehow();
List<String> columns = new ArrayList<String>(wrongDataStructure.keySet()); // Note I expect LinkedHashMap ordering here.
List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
int size = wrongDataStructure.values().iterator().next().size();
for (int i = 0; i < size; i++) {
Map<String, Object> row = new HashMap<String, Object>();
for (String column : columns) {
row.put(column, wrongDataStructure.get(column).get(i).getName());
}
rows.add(row);
}
// Now use "columns" and "rows".
source to share
I couldn't figure out how to do this without using a trick: since the size of your lists on the map can be different for each set of keys, you need to know the size of the list with the largest set of items. Knowing that you can come up with this strange solution: the idea is to have a for loop in a for loop.
private Map<String, List<Foo>> fooMap = Maps.newHashMap();
private List<Foo> highestNumberOfFoos;
private init()
{
highestNumberOfFoos = Lists.newArrayList(new Foo("a", "b"), new Foo("c", "d"), new Foo("e", "f")); // We know that there won't be any list who has more items than this item.
fooMap.put("name1", highestNumberOfFoos);
fooMap.put("name2", Lists.newArrayList(new Foo("g", "h"), new Foo("i", "j")));
}
... and in the view:
<table>
<thead>
<tr>
<ui:repeat value="#{bean.fooMap.keySet().toArray()}" var="key">
<td>#{key}</td>
</ui:repeat>
</tr>
</thead>
<tbody>
<ui:repeat value="#{bean.highestNumberOfFoos}" var="dummyFoo" varStatus="vs">
<tr>
<ui:repeat value="#{bean.fooMap.entrySet().toArray()}" var="innerEntry">
<td>#{innerEntry.value[vs.index].name}</td>
</ui:repeat>
</tr>
</ui:repeat>
</tbody>
</table>
source to share