3
votes

I need to create a table where the headers list are brought from a model. The table contents are also stored in the model and p:dataTable loop on the data to show the content based on the column name.

The issue is that I need to make some specific cells editable. For outputting data there is no problem since I use model method which takes both the entity and the column name and return the correct info from the entity based on the column name. The issue is with inputs of the editable cells which I don't know how to set in the entity.

<p:dataTable id="processTable"  var="entity" value="#{home.process.headerEntities}" tableStyle="width:auto" draggableColumns="true" editable="true" editMode="cell">

    <p:columns value="#{home.process.columns}" var="columnHead" >

        <f:facet name="header">
            <h:outputText value="#{columnHead}"/>
        </f:facet>

        <p:cellEditor>
            <f:facet name="output">
                <h:outputText value="#{home.process.getData(entity, columnHead)}" />
            </f:facet>
            <f:facet name="input">
                <p:inputText value="#{home.process.getData(entity, columnHead)}" rendered="#{home.process.isEditable(columnHead)}"  style="width:100%" />
            </f:facet>
        </p:cellEditor>


    </p:columns>

</p:dataTable>

After change based on BEST ANSWER

<p:dataTable id="processTable"  var="entity" value="#{home.process.headerEntities}" tableStyle="width:auto" draggableColumns="true" editable="true" editMode="cell">

                <p:columns value="#{home.process.columns}" var="columnHead" >

                    <f:facet name="header">
                        <h:outputText value="#{columnHead}"/>
                    </f:facet>

                    <p:cellEditor>
                        <f:facet name="output">
                            <h:outputText value="#{entity[home.process.columnPropertyMap[columnHead]]}" />
                        </f:facet>
                        <f:facet name="input">
                            <p:inputText value="#{entity[home.process.columnPropertyMap[columnHead]]}" rendered="#{home.process.isEditable(columnHead)}"  style="width:100%" />
                        </f:facet>
                    </p:cellEditor>


                </p:columns>

            </p:dataTable>
1
How about binding the dataTable to a backing bean? - Dominik Sandjaja
@DaDaDom: I'd not recommend that. Just use XHTML to declare/create components. It's so much better maintainable than doing that in Java. - BalusC

1 Answers

3
votes

The input component's value must be bound to a writable value expression. What you've there is a direct getter method invocation and thus essentially read-only. This is indeed not going to work. You need to specify a property name of the #{entity}. You can use the brace notation to specify the property name as a variable like so #{entity[propertyName]}.

So, basically:

<p:dataTable value="#{bean.entities}" var="entity" editable="true" editMode="cell">
    <p:columns value="#{bean.propertyNames}" var="propertyNames">
        <p:cellEditor>
            <f:facet name="output">
                #{entity[propertyName]}
            </f:facet>
            <f:facet name="input">
                <p:inputText value="#{entity[propertyName]}" />
            </f:facet>
        </p:cellEditor>
    </p:columns>
</p:dataTable>

As to the column header, rather refactor out that into a Map<String, String> where the key is the propertyName and the value is the header.

        <f:facet name="header">
            #{bean.columnHeaders[propertyName]}
        </f:facet name="header">

Or better yet, use a normal i18n resource bundle for that where the propertyName represents part of the bundle key.

        <f:facet name="header">
            #{bundle['table.column.header.' += propertyName]}
        </f:facet name="header">

As to the editable check, rather wrap propertyName and editable in another bean (and perhaps also columnHeader if you don't want to use a i18n bundle), e.g. Field and then use like below:

    <p:columns value="#{bean.fields}" var="field">
        <p:cellEditor>
            <f:facet name="output">
                #{entity[field.propertyName]}
            </f:facet>
            <f:facet name="input">
                <p:inputText value="#{entity[field.propertyName]}" rendered="#{entity[field.editable]}" />
            </f:facet>
        </p:cellEditor>
    </p:columns>

All in all, it just boils down to preparing and providing the right model the view expects. This way the getData() thing isn't necessary.