14

I'm having a datatable where I would like to set the id of each row to the id of the current item (object that has an id field) in the array that builds the table.

Example:

<h:dataTable
   value="#{bean.list}"
   var="item">
      <h:column>
         <h:outputText id="#{item.id}" .... />
      </h:column>
</h:dataTable>

This doesn't work as I get: javax.servlet.ServletException: Empty id attribute is not allowed.

Is it not possible to set the id this way due to how JSF builds its id's, or am I doing something wrong?

nivis
  • 913
  • 3
  • 17
  • 34
  • It would be better to set the `value` instead of id, but the nature of the problem indicate that your functional requirement is to edit/delete data from a row. If this is right, then you're going with the wrong approach. – Luiggi Mendoza Mar 27 '13 at 14:12
  • The idea was to have an easy way to reference each row where the id is also connected to (referencing) the actual id of the object in the database. – nivis Mar 27 '13 at 14:20

2 Answers2

23

From the JSF UI components, the id and binding attributes are evaluated during view build time, the moment when the XML tree structure in the XHTML/JSP file is to be parsed and converted to a JSF component tree as available by FacesContext#getViewRoot(). However, the <h:dataTable> iterates during view render time, the moment when the JSF component tree needs to produce HTML code by UIViewRoot#encodeAll(). So, at that moment the id attribute is evaluated, the #{item} is nowhere available in the EL scope and evaluates to null which ultimately prints an empty string.

There are basiclly 3 solutions:

  1. Use a view build time tag like JSTL <c:forEach> so that the #{item} is available during view build time as well.

    <table>
        <c:forEach items="#{bean.list}" var="item">
            <tr><td><h:outputText id="#{item.id}" ... />
    

    See further also JSTL in JSF2 Facelets... makes sense?

  2. Don't print it as ID of a JSF component, but of a plain HTML element.

    <span id="#{item.id}">
    

    Please note that IDs starting with a digit are invalid in HTML as per HTML spec chapter 6.2. You might want to prefix it with some string like so:

    <span id="item_#{item.id}">
    
  3. Don't use a dynamic ID. Just use a fixed ID. JSF will autogenerate an unique ID based on row index anyway.

    <h:outputText id="foo" ... />
    

    This will end up in like <span id="formId:tableId:0:foo"> provided that it's inside a <h:form id="formId"><h:dataTable id="tableId">. The 0 is the 0-based row index which increments every row. This thus guarantees an unique ID in every row without the need to worry about it yourself.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks. As I replied to Luiggi I'd like to have some reference to the actual id of the object in the database. This in order to easily scroll to the line from an "external" reference point. Now there's probably a million different ways to achieve that, but I thought that having the actual id from the database would be an easy way to do it. Your proposed solution no 2 will work fine I believe. Once again; thanks! – nivis Mar 27 '13 at 14:26
2

You can't use EL in id attribute in this way. id attribute should be available during view build time but your EL is evaluated during view render time. This is too late, so in moment when id is checked it is empty.

partlov
  • 13,789
  • 6
  • 63
  • 82