10

ページに、AJAX 要求を介してデータ テーブルを更新するボタンがあります。このようなもの:

<h:form id="datatable">
<p:dataTable/>
</h:form>
<p:commandButton update=":datatable">

これは、テーブルが更新されると、以前の値に基づいてソートされていることを示しながら、何もソートしない状態に戻ることを除いて、すべて問題ありません。つまり、ヘッダーは引き続き強調表示され、矢印はまだソート方向を指していますが、実際にはソートは実行されていません。明らかに、これは理想的ではありません。

理想的には、コンポーネントがビューステートでソート順を維持し、AJAX リクエスト中に適切なパラメーターを送信するようにしたいと考えています (ソートが正しく定義されるように)。パラメータか何かがありませんか?他の誰かがこの問題を抱えていますか?

テーブルがソートバックを予期しているときにわかることから、次のオプションがポストされます。

<componentID>_sortDir
<componentID>_sortKey
<componentID>_sorting
<componentID>_updateBody

フォームを更新すると、これは起こりません。また、テーブルを更新するだけでは発生しません (コンポーネントを直接更新することで問題を回避できると考えていました)。テーブルを正しく更新する方法はありますか?

4

8 に答える 8

10

@truemmerのソリューションの拡張機能を作成しました。彼はソート順をデフォルトに戻しますが、私の場合はユーザーが選択した前のソートに戻します。

function postAjaxSortTable(datatable)
{
    var selectedColumn = datatable.jq.find('.ui-state-active');
    if(selectedColumn.length <= 0)
    {
        return;
    }
    var sortorder = "ASCENDING";
    if(selectedColumn.find('.ui-icon-triangle-1-s').length > 0)
    {
        sortorder = "DESCENDING";
    }
    datatable.sort(selectedColumn, sortorder);
}

truemmer の作品と同じテーブルを更新すると、次のようになります。

<p:commandButton value="refresh" action="#{tableController.refreshPrices}" update="myTable" oncomplete="postAjaxSortTable(myTableWidget)" />

編集: Primefaces 4.0 マルチソートのサポート

function postAjaxSortTable(datatable) {
    var selectedColumn = undefined;

    // multisort support
    if(datatable && datatable.cfg.multiSort) {
        if(datatable.sortMeta.length > 0) {
            var lastSort = datatable.sortMeta[datatable.sortMeta.length-1];
            selectedColumn = $(document.getElementById(lastSort.col));
        }
    } else {
        selectedColumn = datatable.jq.find('.ui-state-active');
    }

    // no sorting selected -> quit
    if(!selectedColumn || selectedColumn.length <= 0) {
        return;
    }

    var sortorder = selectedColumn.data('sortorder')||"DESCENDING";
    datatable.sort(selectedColumn, sortorder, datatable.cfg.multiSort);
}
于 2013-03-21T18:08:26.820 に答える
5

まず、PrimeFaces Issue Trackerにオープン チケットがあり、この質問を対象としていますが、最近「修正されません」というラベルが付けられました。

それにもかかわらず、私は素晴らしい回避策を見つけました。PrimeFaces テーブルの並べ替えは、データテーブルのウィジェットで文書化されていない JavaScript メソッドを呼び出すことでトリガーできます。以下は、PrimeFaces の将来のリリースでは機能しない可能性がありますが、3.4.2 では機能します。

以下をコンポーネントに追加するだけで、更新がトリガーされます。

oncomplete="myTableWidget.sort($(PrimeFaces.escapeClientId('#{p:component('sortColumnId')}')), 'ASCENDING')"

テーブルは次のようになります。

<p:dataTable id="myTable"
             widgetVar="myTableWidget"
             value="#{myArticles}"
             var="article"
             sortBy="#{article.price}"
             sortOrder="ASCENDING">
    ...

    <p:column id="price" sortBy="#{article.price}">
        <f:facet name="header">
            <h:outputText value="Price" />
        </f:facet>
        <h:outputText value="#{article.price}" />
    </p:column>

</p:dataTable>

したがって、テーブルの更新は次のように機能します。

<p:commandButton value="refresh" action="#{tableController.refreshPrices}" update="myTable" oncomplete="myTableWidget.sort($(PrimeFaces.escapeClientId('#{p:component('price')}')), 'ASCENDING')" />
于 2013-01-17T09:41:59.720 に答える
3

編集:

以下に投稿されたソリューション (LazyTable) は、LazyDataModel に裏打ちされた p:dataTable で機能します。オーバーライドされたロードメソッドは、目的のテーブルの更新/更新のたびに呼び出され、並べ替えを適切に処理します。単純な p:dataTable の問題は、最初の読み込み時、または並べ替え列をクリックした後にのみ、定義済みの並べ替えを実行することです。これは単純なテーブルの通常の動作です。

それでは、単純なテーブルの可能性は何ですか:

  • 更新後にテーブルを並べ替えないでください。ただし、並べ替え列を削除して、エンド ユーザーに誤解を与えないようにします。これを更新ボタンのアクション リスナーまたはアクション メソッドに追加します。

    UIComponent table  = FacesContext.getCurrentInstance().getViewRoot().findComponent(":dataTablesForm:dataTableId");
    table.setValueExpression("sortBy", null);
    
  • テーブルの並べ替えをスクリプトで手動で更新します。これは最善の解決策ではありませんが、primefaces はテーブルを「再ソート」するためのクライアント側の機能を提供していません。基本的に、一度に 1 つの列のみを並べ替えることができ、この列には .ui-state-active があることがわかっています。スクリプトで使用して、その列で 2 回のクリックをトリガーできます (1. クリック - 他の並べ替え順序、2. クリック - 現在の並べ替え順序に戻る)。

     <h:form id="mainForm">  
    <div id="tableDiv">
       <p:dataTable id="dataTable" var="item" value="#{testBean.dummyItems}">
          .
          .
          .
       </p:dataTable> 
       <p:commandButton value="Refresh" oncomplete="refreshSort();" update=":mainForm:dataTable"/>
     </div>
    

    そしてスクリプト関数:

    function refreshSort(){
    jQuery('#tableDiv').find('.ui-state-active').trigger('click');
    jQuery('#tableDiv').find('.ui-state-active').trigger('click');
    }
    

これが最善の回避策ではないことはわかっていますが、うまくいきます。より良いものを作るためのインスピレーションとして使用できます。

レイジーテーブル

私見の最も適切な方法は、必要なコンポーネントを直接更新することです。たとえば、次のようになります。

<h:form id="dataTableForm">
  <p:dataTable id="dataTableToUpdate">
    .
    .
    .
  </p:dataTable>
  <p:commandButton value="Refresh" update=":dataTableForm:dataTableToUpdate" />
</h:form>

このシナリオでは正常に動作するはずです(それがあなたの目的だと思います):p:dataTableで.xhtmlを開き、いくつかの列をソートし(フェイスレットを開いたままにしてください)、たとえば別の.xhtmlからdataTablesデータを更新し、更新ボタンをクリックします. dataTable は、追加された値を正しい (以前に選択した) 並べ替え順序で表示する必要があります。並べ替えは更新後に実行されました。

それが役に立てば幸いです!

于 2012-04-08T15:21:07.020 に答える
1

この PhaseListener をアプリケーションに追加すると、DataTable の更新後も並べ替えとフィルタリングの両方が保持されます。

public class DataTableUpdatePhaseListener implements PhaseListener {

    private static final long serialVersionUID = 1L;

    @Override
    public void afterPhase(PhaseEvent event) {
        // Nothing to do here
    }

    @Override
    public void beforePhase(PhaseEvent event) {
        FacesContext facesContext = event.getFacesContext();
        if (!facesContext.isPostback()) {
            return;
        }

        PartialViewContext partialViewContext = facesContext.getPartialViewContext();
        if (partialViewContext != null) {
            Collection<String> renderIds = partialViewContext.getRenderIds();

            for (String renderId : renderIds) {
                UIComponent component = facesContext.getViewRoot().findComponent(renderId);
                if (component instanceof DataTable) {
                    DataTable table = (DataTable) component;
                    if (!table.isLazy()) {
                        updateDataTable(table);
                    }
                }
            }
        }
    }

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.RENDER_RESPONSE;
    }

    private void updateDataTable(DataTable table) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext == null || table == null) {
            return;
        }

        // Reapply filtering
        if (!table.getFilters().isEmpty()) {
            FilterFeature filterFeature = new FilterFeature();
            filterFeature.decode(facesContext, table);
        } else {
            table.setFilteredValue(null);
        }

        // Reapply sorting
        ValueExpression tableSortByVE = table.getValueExpression("sortBy");
        if (tableSortByVE != null) {
            String tableSortByExpression = tableSortByVE.getExpressionString();

            // Loop on children, that are the columns, to find the one whose order must be applied.
            for (UIComponent child : table.getChildren()) {
                Column column = (Column) child;
                ValueExpression columnSortByVe = column.getValueExpression("sortBy");
                if (columnSortByVe != null) {
                    String columnSortByExpression = columnSortByVe.getExpressionString();

                    if (tableSortByExpression != null && tableSortByExpression.equals(columnSortByExpression)) {
                        // Now sort table content
                        SortFeature sortFeature = new SortFeature();
                        sortFeature.sort(facesContext, table, tableSortByVE,
                                SortOrder.valueOf(table.getSortOrder().toUpperCase(Locale.ENGLISH)),
                                table.getSortFunction());

                        break;
                    }
                }
            }
        }
    }
}

これは非遅延データ テーブル用です。遅延モデルを使用するデータ テーブルでは、遅延モデルが並べ替えとフィルタリングを処理するため、これは必要ありません。非遅延データ テーブルの場合、これは単一列と複数列の並べ替えの両方で機能するはずですが、Primefaces にはバグがあり、テーブルの更新時にポストバック間で DataTable の MultiSortMeta が失われます。これは、ポストバック前にソート用に選択された列が FacesContext およびコンポーネントの状態から完全に失われ、ポストバック時に取得できなくなることを意味します。これについては後で詳しく調べて、回避策を見つけることができた場合、または Primefaces がすぐに修正する可能性がある場合は、更新を提供します。

于 2013-09-23T07:27:45.417 に答える
0

toString() メソッドで Comparator を実装します

municipios = municipioFacade.findAll();
Collections.sort(municipios, new DefaultComparator());
UIComponent table = FacesContext.getCurrentInstance().getViewRoot().findComponent(":municipios:municipios-tabla");
    table.setValueExpression("sortBy", null);

コンパレータ

public class DefaultComparator implements Comparator {

    @Override
    public int compare(Object o1, Object o2) {
        return o1.toString().compareToIgnoreCase(o2.toString());
    }
}
于 2012-05-02T18:40:24.853 に答える
0

私はあなたと同じ問題を抱えていました。LazyDataModelを使用して問題を修正できました。行インデックスに関する PrimeFaces の問題のため、追加の UtilitiesLazyDataModel を追加する必要がありました (行インデックスのコメントを参照)。

public abstract class UtilitiesLazyDataModel <T> extends LazyDataModel<T>{

    public UtilitiesLazyDataModel() {
    }    

    @Override
    public void setRowIndex(int rowIndex) {
        /*
         * The following is in ancestor (LazyDataModel):
         * this.rowIndex = rowIndex == -1 ? rowIndex : (rowIndex % pageSize);
         */
        if (rowIndex == -1 || getPageSize() == 0) {
            super.setRowIndex(-1);
        } else {
            super.setRowIndex(rowIndex % getPageSize());
        }      
    }
}

次にLazyDataModel、これでクラスを使用します。

public class MyDataModel extends UtilitiesLazyDataModel<MyObjectClass>{

//override getRowData and getRowKey

}
于 2013-03-21T21:42:06.203 に答える
0

解決策は、会話型 Bean を使用することです。この場合、p:dataTable は、並べ替え順序に影響を与えることなく、テーブルとそのエントリを更新します。各行に ap:commandButton がある場合、テーブルの更新も正しく機能します。

会話型 Bean:

@Named
@Stateful
@ConversationScoped
public class ItemBean {

    @Inject
    private Conversation conversation;

    private List<Item> items;

    public List<Item> getItems() {
        return this.items;
    }

    public void retrieve() {
        // if it's an Ajax call then avoid retrieving items
        if (FacesContext.getCurrentInstance().isPostback()) {
            return;
        }
        // start a conversation
        if (this.conversation.isTransient()) {
            this.conversation.begin();
        }
        this.items = retrieveItems();
    }
}

関連ページ:

<f:metadata>
    <f:event type="preRenderView" listener="#{itemBean.retrieve}" />
</f:metadata>

<h:form id="form">
    <p:dataTable id="table" var="_item" value="#{testBean.items}">
    ... <!-- you can have the p:commandButton in a column too, to refresh the respective column only
        <p:commandButton value="Refresh" action="#{itemBean.update(_item)}" 
        -->
    </p:dataTable> 
    <p:commandButton value="Refresh" action="#{itemBean.update}" update=":form:table"/>
</h:form>
于 2012-05-13T21:38:56.657 に答える
0

@Rares Oltean のアプローチは、preRenderView イベント リスナーを使用して実装することもできます。jsf ページでリスナーを登録します。

<f:event listener="#{managedBean.preRenderViewListener}" type="preRenderView" />

それを ManagedBean に実装します。

public void preRenderViewListener() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    if (!facesContext.isPostback()) {
        return;
    }

    PartialViewContext partialViewContext = facesContext.getPartialViewContext();
    if (partialViewContext != null) {
        Collection<String> renderIds = partialViewContext.getRenderIds();

        for (String renderId : renderIds) {
            UIComponent component = facesContext.getViewRoot().findComponent(renderId);
            if (component instanceof DataTable) {
                DataTable table = (DataTable) component;
                if (!table.isLazy()) {
                    updateDataTable(table);
                }
            }
        }
    }
}

private void updateDataTable(DataTable table) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    if (facesContext == null || table == null) {
        return;
    }
    if (!table.getFilters().isEmpty()) {
        FilterFeature filterFeature = new FilterFeature();
        filterFeature.decode(facesContext, table);
    } else {
        table.setFilteredValue(null);
    }
    ValueExpression tableSortByVE = table.getValueExpression("sortBy");
    if (tableSortByVE != null) {
        String tableSortByExpression = tableSortByVE.getExpressionString();
        for (UIComponent child : table.getChildren()) {
            Column column = (Column) child;
            ValueExpression columnSortByVe = column.getValueExpression("sortBy");
            if (columnSortByVe != null) {
                String columnSortByExpression = columnSortByVe.getExpressionString();
                if (tableSortByExpression != null && tableSortByExpression.equals(columnSortByExpression)) {
                    SortFeature sortFeature = new SortFeature();
                    sortFeature.sort(facesContext, table, tableSortByVE, table.getVar(),
                            SortOrder.valueOf(table.getSortOrder().toUpperCase(Locale.ENGLISH)),
                            table.getSortFunction());
                    break;
                }
            }
        }
    }
}
于 2015-04-03T13:26:14.000 に答える