在<p:ajax event="cellEdit">完成后更新整个<p:dataTable>

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。


你尝试过将 update=":testForm:testContainer" 更改为 update=":testForm:testTable" 吗? - Joffrey Hernandez
刚刚尝试了一下,但只有当前单元格在更新。 - Franzl
7个回答

62
rowEditcellEdit事件在表格内部被设计为仅更新/重新渲染当前行,即使在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>

@BalusC,我按照您的指导操作了,但是Glassfish Server提示错误,说找不到该方法,需要说明该方法包含CellEditEvent参数,正如Tim Long所说。当单元格被编辑时,我想要更新整个数据表。您能帮我吗? - elgolondrino
有人向Primefaces报告过这个问题吗?我们拥有Primefaces PRO并愿意升级。 - Greg Noe
8
简单地感谢一下:“谢谢”。我本来觉得自己疯了。对我而言,我保留了ajax的“cellEdit”监听器,然后只是将“update”属性移到了“remoteCommand”中,没有在“remoteCommand”组件中执行任何操作,基本上只使用它来执行我所使用的ajax事件所需的“update”属性。 - Doug
@BalusC 这个解决方案仅在使用回车键完成单元格编辑时有效。如果一个单元格处于编辑模式,而另一个可编辑的单元格被点击,则将触发单元格编辑事件并更新表格,但不再可编辑! - ltlBeBoy
这个问题已经存在了8年多,但现在仍然存在。 - Az.MaYo

29

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

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

你的方法可以工作,但只能编辑一个“单元格”?如何解决这个问题? - elgolondrino
在我的情况下,BaLusC的解决方案适用于我在可编辑表格中拥有的inputText。如果更改是在单元格内的自动完成控件中完成的,则整个表格不会更新。使用remoteCommand解决方案,它可以正常工作。 - Richard P.
BaLusC的解决方案对我也不起作用。这个解决方案完美地解决了问题! - Alessio Fiore
现在已经过去8年了,这个问题仍然存在。您的解决方案节省了我的时间,谢谢。 - Az.MaYo

6
如果以上解决方案都没有帮助到您,这个方法对我有效。
<p:dataTable ... id="theId" widgetVar="theWidget" ...>
                <p:ajax event="rowEdit" listener="#{...}"
                        oncomplete="PF('theWidget').filter()"/> 
....

我在ajax完成后调用PF小部件的过滤方法,任何重新加载表格的方法都应该可以工作,我使用了过滤器,因为我的表格有列过滤器。


0
五年过去了,这个问题仍然存在。不幸的是,虽然Baukes的解决方案非常有帮助并包含重要见解,但它仍然不完整,正如ltlBeBoy在他的评论中指出的那样。没有更改的后续编辑会导致不一致的表状态,无法进行更多编辑。原因是oncomplete远程更新在新单元格的编辑模式已经激活之后才到来。因此,新单元格的编辑模式被更新破坏了。但是,在Ajax监听器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}"/>

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事件成功后。干杯!

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构造函数加载基本数据并删除新数据。

basic data

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

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

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

我不知道您的目标是什么。如果您想要渲染没有commandButton的表格,则可以指定一个javascript事件或p:message,这样就可以消除您可以渲染表格的问题。

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


0

尝试使用process

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接