问题描述:

I want to allow user to edit cells in data table only if some condition is met.

Initially I have tried <choose> to achieve this:

<p:dataTable var="item" value="${bean.items}" editable="true" editMode="cell">

<p:column headerText="column A">

<c:choose>

<c:when test="${item.isEditable}">

<p:cellEditor id="title">

<f:facet name="output">

<h:outputText value="#{item.title}"/>

</f:facet>

<f:facet name="input">

<p:inputText value="#{item.title}"/>

</f:facet>

</p:cellEditor>

</c:when>

<c:otherwise>

<h:outputText value="#{item.title}"/>

</c:otherwise>

</c:choose>

</p:column>

...

but it does not work. Another approach is to use rendered attribute:

<p:column headerText="column A">

<p:cellEditor rendered="${item.isEditable}">

<f:facet name="output">

<h:outputText value="#{item.title}"/>

</f:facet>

<f:facet name="input">

<p:inputText value="#{item.title}"/>

</f:facet>

</p:cellEditor>

<h:outputText value="#{item.title}" rendered="#{!item.isEditable}"/>

</p:column>

that works fine - user are able to edit only allowed cells.

But even if cell is not editable it still has ui-cell-editing class and looks like editable cell for user.

What is a correct way to apply condition to cell editing?

Thank you!

网友答案:

To properly learn the lesson of JSTL fail, it failed for the reason explained in the following answer: JSTL in JSF2 Facelets... makes sense? In a nutshell: #{item} isn't available at the moment JSTL runs.

Coming back to the concrete question: that style class is been inserted due to the combination editMode="cell" and the physical presence of <p:cellEditor> component in the <p:column>. The PrimeFaces datatable renderer isn't at all considering if the <p:cellEditor> is rendered or not. It just outright inserts the ui-editable-column style class which in turn triggers the ui-cell-editing style via JS/jQuery. You were looking in the right direction for the solution, JSTL which can conditionally physically add/remove JSF components in the JSF component tree, but unfortunately it won't work in this construct.

Your best bet is to post an issue report to the PrimeFaces guys whereby you ask to not only consider the physical presence of <p:cellEditor> component, but also its isRendered() outcome. Considering PrimeFaces version 3.5, that would be in line 796 of DataTableRenderer class which originally looks like this (newlines introduced for readability):

String styleClass = selectionEnabled 
    ? DataTable.SELECTION_COLUMN_CLASS 
    : (column.getCellEditor() != null) 
        ? DataTable.EDITABLE_COLUMN_CLASS 
        : null;

And should be modified as follows:

String styleClass = selectionEnabled 
    ? DataTable.SELECTION_COLUMN_CLASS 
    : (column.getCellEditor() != null && column.getCellEditor().isRendered()) 
        ? DataTable.EDITABLE_COLUMN_CLASS 
        : null;

If you can't wait, in the meanwhile you could homegrow a custom renderer.

package com.example;

import org.primefaces.component.datatable.DataTableRenderer;

public class MyDataTableRenderer extends DataTableRenderer {

    @Override
    protected void encodeCell(FacesContext context, DataTable table, UIColumn column, String clientId, boolean selected) throws IOException {
        // Copypaste here the original encodeCell() source code and make modifications where necessary.
    }

}

Then, to get it to run, register it as follows in faces-config.xml:

<render-kit>
    <renderer>
        <description>Overrides the PrimeFaces table renderer with customized cell renderer.</description>
        <component-family>org.primefaces.component</component-family>
        <renderer-type>org.primefaces.component.DataTableRenderer</renderer-type>
        <renderer-class>com.example.MyDataTableRenderer</renderer-class>
    </renderer>
</render-kit>
相关阅读:
Top