Reputation: 3381
I'm trying to iterate through a List of Map items, i.e. an ArrayList of HashMaps or something similar, and I'm trying to do this in primefaces datatable. This is basically what I'm trying to do:
<body>
<h:form>
<p:dataTable value="#{customerBean.list}" var="map">
<c:forEach items="#{map}" var="entry">
<p:column headerText="#{entry.key}">
#{entry.value}
</p:column>
</c:forEach>
</p:dataTable>
</h:form>
</body>
In this case, customerBean.list
is a List<Map<String, String>>
and entry is a Map<String, String>
.
What I want to do, is create a dynamic amount of columns, based on the amount of entries in a Map<String, String>
while using the map entry's key as a header name, and the value as the output. The c:forEach
thing seems to work fine when I'm using a hardcoded Map<String, String>
, but apparently it can't loop through the var of the p:dataTable
. I assume that the program takes precaution to avoid having to loop through Maps of different sizes. So how can I make this work anyway? How can I create an arbitrary amount of columns based on the amount of entries in a Map? Note that I'm a 100% certain that every Map<String, String>
is of equal size in my List<Map<String, String>>
EDIT:
Here's my bean source. The code works fine and everything, the problem is just with the loop not willing to go through my map:
@ManagedBean
@SessionScoped
public class CustomerBean {
private List<Map<String, String>> list = new ArrayList<Map<String, String>>();
private Mapper mapper = new Mapper();
public CustomerBean() {
list = mapper.all(); //gets data from database
}
public List<Map<String, String>> getList() {
return list;
}
public void setList(List<Map<String, String>> list) {
this.list = list;
}
}
Upvotes: 2
Views: 12415
Reputation: 11742
The problem is unrelated to the Map
usage in this context. The problem is that you're trying to get a #{map}
variable that's only available when view is being rendered, but you're relying on its value at the moment when view is being built. The latter is performed on an earlier lifecycle phase, so it is basically unavailable when you demand it.
Still, tag handler, or view build tag, like <c:forEach>
, is the only way to populate the variable number of columns, as <p:column>
is assessed when component tree is being built.
Another thing worth noting is that the backing bean bound to <c:forEach>
tag's property, such as items
, must be anything but view scoped, like request scoped, otherwise it will be recreated upon every request which will bring unexpected/undesired results, as the demanded bean is not there when you try to access its properties. There are some other setup constellations solving this issue, but they're not the subject of discussion here.
<p:dataTable value="#{customerBean.list}" var="map">
<c:forEach items="#{forEachBean.columnsMap}" var="entry">
<p:column headerText="#{entry.key}">
#{map[entry.key]}
</p:column>
</c:forEach>
</p:dataTable>
Also worth noting that there is a helper <p:columns>
component that does roughly the same.
Upvotes: 5