Iterating through List<Map<String, String>> in primefaces datatable?

11,731

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.

Share:
11,731
ZimZim
Author by

ZimZim

Just an intermediate Java programmer looking to improve.

Updated on June 05, 2022

Comments

  • ZimZim
    ZimZim almost 2 years

    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;
        } 
    }
    
  • ZimZim
    ZimZim almost 11 years
    I just put a variable containing the columns in the customerBean itself. It works like a charm. I didn't know the value of a map could be accessed the way you did it (#{map[entry.key]} but apparently it works great. Thanks a lot!