4

In my application I want to display a <h:dataTable> with managed bean properties. Currently this table is created from a List<Folder>. Now I want to change the Folder to something more dynamic. That's because I don't want to change the Folder class if I decide to add another field later. I would just have to add another entry in the Map<String, Object> instead of introducing a new field in Folder.

So, is it possible to bind a List<Map<String, Object>> to the <h:dataTable>?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
nico1510
  • 606
  • 9
  • 29

1 Answers1

5

Is it possible to bind a List of HashMaps to the jsf component h:dataTable?

That's only possible if you generate the necessary <h:column> tags with a view build time tag such as JSTL <c:forEach>.

Here's a concrete kickoff example, assuming that your environment supports EL 2.2:

<h:dataTable value="#{bean.listOfMaps}" var="map">
    <c:forEach items="#{bean.listOfMaps[0].keySet().toArray()}" var="key">
        <h:column>
            #{map[key]}
        </h:column> 
    </c:forEach>
</h:dataTable>

(if your environment doesn't support EL 2.2, you'd need to provide another getter which returns the map key set as a String[] or List<String>; also keep in mind that a HashMap is by nature unordered, you might want to use LinkedHashMap instead to maintain insertion order)

When you're using Mojarra version older than 2.1.18, the disadvantage is that the #{bean} has to be request scoped (not view scoped). Or at least, the <c:forEach items> should refer a request scoped bean. A view scoped bean would otherwise be recreated on every single HTTP request as the <c:forEach> runs during view build time, when the view scope isn't availabe yet. If you absolutely need a view scoped bean for the <h:dataTable>, then you can always create a separate request scoped bean exclusively for <c:forEach items>. The solution would be to upgrade to Mojarra 2.1.18 or newer. For some background information, see also JSTL in JSF2 Facelets... makes sense?

JSF component libraries such as PrimeFaces may offer a <x:columns> tag which makes this more easy, such as <p:dataTable> with <p:columns>.

<p:dataTable value="#{bean.listOfMaps}" var="map">
    <p:columns value="#{bean.listOfMaps[0].keySet().toArray()}" var="key">
        #{map[key]}
    </p:columns>
</p:dataTable>
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • ah great that's what I was looking for. The only annoying thing is that I have to use the forEach. Somewhere I read that one could also implement some interface (don't remember the name) for your own data structure so that jsf knows how to render it. Is this possible or did I get something wrong there? – nico1510 Nov 01 '12 at 13:07
  • I think you get it wrong :) For the ``, the `UIColumn` children have really to be populated during view build time. The `` is the only available iteration tag which runs during view build time. – BalusC Nov 01 '12 at 13:09