web-dev-qa-db-ja.com

<p:ajax event = "cellEdit">の完了時に<p:dataTable>全体を更新する

セルを編集すると、PrimeFaces Datatableを再レンダリングするのが困難になります。 1つのセルの値を変更すると、他のセルのエントリが変更される可能性があるため、テーブル全体を更新する必要があります。

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イベント内でupdate属性を指定せず、セルの値を編集した後に[再表示]ボタンをクリックすることにより、(自動化されていない方法で)目的の動作を実現できます。自動化された方法で、なぜupdate属性が期待どおりに機能しないのですか?

PrimeFaces 4.0を使用しています。

32
Franzl

rowEditおよび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>
56
BalusC

BaLusCソリューションは私には直接働きませんでした。 onCellEditには、パラメーターとしてCellEditEventが必要です。私の回避策は次のとおりです。

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

解決策がどれもうまくいかなかった場合、これは私のために働いた

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

私はajax completeのPFウィジェットでフィルターメソッドを呼び出していますが、テーブルの「リロード」を行うメソッドはすべて動作するはずです。テーブルには列フィルターがあるため、filterを使用しました。

5
Lance Reid

コードをテストしました。まず、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"は、例外としてoutputPanelを更新するため、ajaxになります(プログラムが何度もテーブルを更新するため、1回目は正しく動作し、2回目はセルを編集できませんでした)。

あなたの目標は何なのか分かりません。 commandButtonなしでテーブルをレンダリングする場合、1つのjavascriptイベントまたはp:messageを指定すると、テーブルがレンダリングできなくなります。

P:ajaxでupdateを省略するか、p:messageの更新を1つ指定して、p.commandButtonをtestContainerから移動すると、コードが正しく動作するようになります。

0
herry

5年後、この問題はまだ存在します。残念ながら、Baukesのソリューションは非常に有用であり、重要な洞察を含んでいますが、ltlBeBoyが既にコメントで指摘しているように、まだ不完全です。変更を伴わない後続の編集により、一貫性のないテーブル状態が発生し、それ以上編集できなくなります。その理由は、新しいセルの編集モードがすでにアクティブになった後で、oncompleteリモート更新が行われるためです。そのため、新しいセルの編集モードは更新によって破棄されます。ただし、Ajaxリスナーで更新を行うことはできませんtableBean#onCellEdit。これは、1つのセルのみで誤ってテーブルを表示するためです。

解決策は、変更が発生した場合にのみ、リモートコマンドリスナーで更新を実行することです。したがって、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
Marc Dzaebel