38

编辑单元格后,我很难重新渲染 PrimeFaces 数据表。更改一个单元格中的值可能会更改其他单元格中的条目,因此需要刷新整个表格。

这是 JSF 页面:

<h:form id="testForm">
    <p:outputPanel id="testContainer">

        <p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">

            <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />

            <p:column headerText="Col1">  
                <p:cellEditor>
                    <f:facet name="output"><h:outputText value="#{entry.col1}" /></f:facet>
                    <f:facet name="input"><p:inputText value="#{entry.col1}" /></f:facet>
                </p:cellEditor> 
            </p:column>

            <p:column headerText="Col2">
                <p:cellEditor>
                    <f:facet name="output"><h:outputText value="#{entry.col2}" /></f:facet>
                    <f:facet name="input"><p:inputText value="#{entry.col2}" /></f:facet>
                </p:cellEditor>  
            </p:column>

        </p:dataTable>

        <p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />

    </p:outputPanel>                                    
</h:form>

这是支持bean:

@ManagedBean(name = "tableBean", eager = false)
@ViewScoped 
public class TableBean {

    public TableBean() {
        RowData entry = new RowData("a1", "b1");
        entries.add(entry);
        entry = new RowData("a2", "b2");
        entries.add(entry);
        entry = new RowData("a3", "b3");
        entries.add(entry);
    }

    public class RowData {

        private String col1;
        private String col2;

        public RowData(String col1, String col2) {
            this.col1 = col1;
            this.col2 = col2;
        }

        public String getCol1() {
            return col1;
        }

        public void setCol1(String col1) {
            this.col1 = col1;
        }

        public String getCol2() {
            return col2;
        }

        public void setCol2(String col2) {
            this.col2 = col2;
        }
    }

    private ArrayList<RowData> entries = new ArrayList<RowData>();

    public List<RowData> getData() {
        return entries;
    }

    public void onCellEdit(CellEditEvent event) {
        entries.get(event.getRowIndex()).setCol1("Dummy Col 1");
        entries.get(event.getRowIndex()).setCol2("Dummy Col 2");        
    }   
}

当在 cellEdit AJAX 事件中包含 update=":testForm:testContainer" 时,更改单元格值会删除屏幕上的数据表,并且只呈现单元格内容(连同按钮)——我不明白这是为什么。当未指定更新属性时,表格将保留在屏幕上,活动单元格已更新,但其他单元格均未更新(正如预期的那样)。

通过在 AJAX cellEdit 事件中不指定更新属性并在编辑单元格的值后单击重新显示按钮,可以实现所需的行为(以非自动方式)。我怎样才能以自动化的方式实现这一点,为什么更新属性不能按我的预期工作?

我正在使用 PrimeFaces 4.0。

4

8 回答 8

60

rowEditand事件在表内的cellEdit设计上不会更新/重新呈现除当前行之外的任何其他内容,即使在update属性中明确指定时也不会。这是 PrimeFaces 过于热心地尝试最小化响应大小的结果。这在大多数情况下都有意义,但不适用于您的具体情况。值得一份问题报告。

同时,在他们修复此行为之前,您最好的办法是使用<p:remoteCommand>调用所需的侦听器方法并执行表的完整更新。

改写

<p:dataTable ...>
    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />
    ...
</p:dataTable>

<p:remoteCommand name="onCellEdit" action="#{tableBean.onCellEdit}" update="testContainer" />
<p:dataTable ...>
    <p:ajax event="cellEdit" oncomplete="onCellEdit()" />
    ...
</p:dataTable>
于 2013-11-12T11:10:48.613 回答
26

BaLusC 解决方案并没有直接为我工作。onCellEdit 需要一个 CellEditEvent 作为参数。我的解决方法如下:

<p:remoteCommand name="onCellEdit" update="testContainer" />
<p:dataTable ...>
    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete="onCellEdit()" />
    ...
</p:dataTable>
于 2014-10-07T14:59:28.703 回答
6

如果没有一个解决方案对你有用,这对我有用

<p:dataTable ... id="theId" widgetVar="theWidget" ...>
                <p:ajax event="rowEdit" listener="#{...}"
                        oncomplete="PF('theWidget').filter()"/> 
....

我在 ajax 完成时调用 PF 小部件上的过滤器方法,任何对表进行“重新加载”的方法都应该起作用,我使用了过滤器,因为我的表有列过滤器。

于 2016-06-15T13:42:53.170 回答
0

我测试了你的代码。首先,我将 p:commandButton 从 p:outputPanel 中移出。这是修改后的代码:

<h:form id="testForm">
            <p:outputPanel id="testContainer">

                <p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">

                    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />

                    (...)

                </p:dataTable>
            </p:outputPanel>
            <p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />
        </h:form>

我认为这段代码不能正常工作。如果您更改表中的任何内容,则 p:ajax 每次都会呈现完整的表。因此,程序从 TableBean 构造函数中加载基本数据并删除了新数据。

基本数据

如果我省略了您的 p:ajax 代码,则不会从屏幕上消失任何新数据。p : refreshButtoncommandButton 工作正常。

当在 cellEdit AJAX 事件中包含 update=":testForm:testContainer" 时,更改单元格值会删除屏幕上的数据表,并且只呈现单元格内容(连同按钮)——我不明白这是为什么。

我认为添加update=":testForm:testContainer"到 ajax 是不好的设计,因为它对 outputPanel 的更新超过了 exepted(第一次正常工作,第二次无法编辑单元格,因为程序更新到多次表)。

我不知道你的目标是什么。如果您想要在没有命令按钮的情况下呈现表格,那么您可以指定一个 javascript 事件或 p:message 并且这个消失您可以呈现表格。

我认为如果您在 p:ajax 中省略更新或指定更新一个 p:message,并将 p.commandButton 从testContainer代码中移出,则可以正常工作。

于 2013-11-02T12:09:44.057 回答
0

尝试使用过程

<p:remoteCommand name="onCellEdit" update="testContainer" process="@this" /> <p:dataTable ...> <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete ="onCellEdit()" 进程="@this" /> ... </p:dataTable>

于 2021-06-15T15:02:57.397 回答
0

这是我在这里的第一篇文章。正如 ltlBeBoy 所提到的,BalusC 的解决方案只有在单元格编辑通过回车键完成时才有效。此处列出的其他建议均不适合我。就我而言,我只想在 cellEdit 事件上更新表中的特定行(具有每列的平均值)。如果有人正在寻找解决方案,我会发布此信息:我设法通过在主数据表正下方的第二个数据表中分离该行来实现这一点。这是代码:

<pf:ajax event="cellEdit"
         listener="#{newAgentMetricBacking.onCellEdit}"
         update="c21413" />

<pf:dataTable id="c21413"
              styleClass="noHeader"
              value="">
    <pf:column>
        <h:outputText value="#{bundle.TeamAverage}"/>
    </pf:column>
    <pf:columns columnIndexVar="j"
                value="#{newAgentMetricBacking.averageArray}"
                var="avg">
        <h:outputText value="#{newAgentMetricBacking. 
                               averageArray[j]}"/>
    </pf:columns>
</pf:dataTable>

否则,截至今天,我找不到更好的解决方案来更新整个表或特定行,特别是在 cellEdit 事件成功后。干杯!

于 2022-01-14T21:56:25.047 回答
0

解决方案是使用

  1. 一个NamingContainer就像p:outputPanel每个要更新的单元格的列子项(对于具有单元格编辑器的列来说不是必需的)
  2. 搜索@row 表达式

使用该解决方案无需使用p:remoteCommand,因为其他行/单元格的更新可以直接由处理的方法触发CellEditEvent

看法:

<p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">

    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />

    <p:column headerText="Col1">
        <!--'p:cellEditor' or e.g. 'p:outputPanel' if cell should be updated, but not editable-->
        <p:cellEditor>
            <f:facet name="output"><h:outputText value="#{entry.col1}" /></f:facet>
            <f:facet name="input"><p:inputText value="#{entry.col1}" /></f:facet>
        </p:cellEditor> 
    </p:column>

    <p:column headerText="Col2">
        <!--'p:cellEditor' or e.g. 'p:outputPanel' if cell should be updated, but not editable-->
        <p:cellEditor>
            <f:facet name="output"><h:outputText value="#{entry.col2}" /></f:facet>
            <f:facet name="input"><p:inputText value="#{entry.col2}" /></f:facet>
        </p:cellEditor>  
    </p:column>

</p:dataTable>

支持豆:

public void onCellEdit(CellEditEvent event) {
    final DataTable dataTable = (DataTable) event.getComponent();
    final String tableId = dataTable.getClientId();
    final int rowIdx = event.getRowIndex();

    // update model
    entries.get(rowIdx).setCol1("Dummy Col 1");
    entries.get(rowIdx).setCol2("Dummy Col 2");

    // update view (cells in edited row)
    final FacesContext context = FacesContext.getCurrentInstance();
    final String rowSearchExpr = tableId + ":@row(" + rowIdx + ")";
    final String cellClientIds = SearchExpressionFacade.resolveClientIds(context, context.getViewRoot(), rowSearchExpr);
    Arrays.stream(cellClientIds.split(" "))
                .forEach(clientId -> context.getPartialViewContext().getRenderIds().add(clientId));
}

详细解释:

灵感来自:

于 2022-03-05T21:32:46.363 回答
0

5年后,这个问题依然存在。不幸的是,正如 ltlBeBoy 在评论中指出的那样,尽管 Baukes 解决方案非常有用并且包含重要的见解,但它仍然不完整。没有更改的后续编辑会导致表格状态不一致,无法进行更多编辑。原因是,oncomplete远程更新是在新单元格的编辑模式已经激活之后进行的。所以新单元格的编辑模式被更新破坏了。但是,不能在 Ajax listener 中进行更新tableBean#onCellEdit,因为这会错误地仅显示一个单元格的表格。

解决方案是,仅在发生更改时才在远程命令侦听器中执行更新。因此,在tableBean您实现编程更新、远程侦听器和指示更改的标志时:

public static void update(String id) {
   PrimeFaces pf = PrimeFaces.current(); //RequestContext.getCurrentInstance() for <PF 6.2
   if(pf.isAjaxRequest()) pf.ajax().update(id);
}

/** Whether onCellEdit changed the value */
boolean onCellEditChange;

public void onCellEditRemote() { 
    if(!onCellEditChange) update("testContainer");
}

public void onCellEdit(CellEditEvent event) {
    ...  onCellEditChange= /*Change happend*/ ...
}

远程命令不再具有更新属性:

<p:remoteCommand name="onCellEdit" actionListener="#{tabelBean.onCellEditRemote}"/>
于 2018-10-15T07:57:25.090 回答