p: datatable теряет столбец сортировки и порядок после обновления ajax

У меня есть кнопка на странице, которая вызывает обновление таблицы данных с помощью запроса AJAX. Что-то вроде этого:

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

Это все прекрасно, за исключением того, что когда таблица обновляется, она возвращается к тому, чтобы ничего не сортировать, в то же время показывая, что она сортируется на основе предыдущего значения. Другими словами, заголовок все еще подсвечивается, а стрелка все еще указывает в направлении сортировки, но сортировка фактически не выполняется. Очевидно, что это не идеально.

В идеале мне бы хотелось, чтобы компонент поддерживал порядок сортировки в состоянии просмотра, а затем отправлял правильные параметры во время запроса AJAX (чтобы сортировка была правильно определена). Я пропускаю параметр или что-то? У кого-нибудь еще есть эта проблема?

Из того, что я могу сказать, когда таблица ожидает сортировки, она публикует следующие параметры:

<code><componentID>_sortDir
<componentID>_sortKey
<componentID>_sorting
<componentID>_updateBody
</code>

Когда я обновляю форму, этого не происходит. Этого также не произойдет, если я просто обновлю таблицу (хотя я мог бы обойти все, обновив компонент напрямую). Есть ли способ заставить таблицу обновляться правильно?

Ответы на вопрос(8)

EDIT:

Приведенное ниже решение (LazyTable) работает для таблицы p: dataTable, поддерживаемой LazyDataModel. переопределеноload Метод вызывается после каждого обновления / обновления в нужной таблице и правильно обрабатывает сортировку. Проблема с простым p: dataTable заключается в том, что он выполняет предопределенную сортировку только при первой загрузке или после щелчка по столбцу сортировки. Это нормальное поведение простой таблицы.

Итак, каковы ваши возможности для простой таблицы:

Don't sort the table after update, but remove the sort column so end user is not missinformed. Add this to your action listener or action method for your update button :

UIComponent table  = FacesContext.getCurrentInstance().getViewRoot().findComponent(":dataTablesForm:dataTableId");
table.setValueExpression("sortBy", null);

Update the sort of the table manually by script. This is not the best solution, but primefaces doesn't provide any client side function for "resorting" the table. Basically you know that only one column at a time can be sorted and this column has a .ui-state-active. You can use it in a script and trigger 2 clicks on that column (1. click - other sort order, 2. click - back to current sort order).

 <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>

And script function :

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

Я знаю, что это не лучший обходной путь, но он работает. Вы можете использовать это как вдохновение, чтобы сделать что-то лучше.

LazyTable

ИМХО самый правильный способ - это обновить непосредственно компонент, который вы хотите. Так, например:

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

Это должно нормально работать в этом сценарии (я полагаю, это ваша цель): Откройте .xhtml с помощью p: dataTable, отсортируйте какой-нибудь столбец (оставьте открытым лицевую панель), обновите данные dataTables, например, из другого .xhtml, нажмите кнопку обновления. В dataTable должно отображаться добавленное вами значение в правильном (ранее выбранном) порядке сортировки - сортировка была выполнена после обновления.

Надеюсь, это помогло!

 10 апр. 2012 г., 22:32
Я отредактировал ответ, дайте мне знать, если он работает для вас.
 08 июн. 2012 г., 06:20
Ну, вариант с отложенной таблицей не работает для меня. Если я обновлю таблицу, сортировка сбрасывается. Мне придется протестировать другой вариант, но я полагаю, что он будет работать. Что делает удаление сорта?
 jjross09 апр. 2012 г., 17:27
Таким образом, вид поддерживается для вас? Или кнопка сортировки только подсвечена, но фактическая сортировка - это порядок сортировки объектов в памяти? Я попытался обновить DT напрямую, и это не повлияло на меня.
 09 апр. 2012 г., 21:54
Кнопка сортировки подсвечена, и сортировка выполнена правильно. Объекты сортируются иначе, чем в памяти - в зависимости от фактического порядка сортировки. Я попробовал его для опубликованного сценария, и он работает совершенно нормально для меня. Какую область вы используете для bean-компонента dataTable?
 jjross09 апр. 2012 г., 23:16
Бин - это область видимости, поэтому я предполагаю, что она должна работать.

Прежде всего, есть открытый билет на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')" />
 12 мая 2017 г., 09:48
В PF6.1 сортировщик должен быть числом: 1 / -1 для «ASCENDING» apos; / 'DESCENDING'.

Подход @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;
                }
            }
        }
    }
}

У меня была такая же проблема, как и у вас. Я смог решить проблему с помощью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

}

Я реализую Comparator с моим методом toString ()

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

comparator

public class DefaultComparator implements Comparator {

    @Override
    public int compare(Object o1, Object o2) {
        return o1.toString().compareToIgnoreCase(o2.toString());
    }
}

Решение состоит в том, чтобы иметь диалоговый компонент. В этом случае p: dataTable обновляет таблицу и ее записи, не влияя на порядок сортировки. В случае, когда в каждой строке есть p: commandButton, обновление таблицы также работает корректно.

Боб разговорный:

@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>
 jjross08 июн. 2012 г., 06:21
Так как же это работает?

Я написал расширение для решения @ 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 MultiSort

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);
}
 26 июн. 2013 г., 15:48
До сих пор работает под PrimeFaces 3.5.
 23 мар. 2013 г., 14:38
Хорошее решение. Я скоро обновлюсь до 3.5 и попробую :) В текущем выпуске было много рефакторинга для таблиц.
 28 февр. 2014 г., 10:26
@ AlvaroCachoperro, я только что отредактировал для поддержки мультисортировки
 25 февр. 2014 г., 10:58
Все еще работает под PrimeFaces 4.0, но я пытаюсь улучшить его для управления мультисортировкой
 26 мар. 2013 г., 20:53
Я должен отметить, что я использовал это в 3.4.2. Я не знаю, работает ли это очень хорошо или нет в 3.5. *, Но я сомневаюсь, что буду обновляться еще.

Добавьте этот 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 исправит это в ближайшее время.

Ваш ответ на вопрос