我在页面上有一个按钮,可以通过AJAX请求刷新我的数据表。像这样:
<h:form id="datatable">
<p:dataTable/>
</h:form>
<p:commandButton update=":datatable">
这一切都很好,但是当表刷新时,它会恢复到不排序任何东西,同时仍然显示它是基于前一个值进行排序的。换句话说,标题仍然突出显示,箭头仍指向排序方向,但实际上没有执行排序。显然这并不理想。
理想情况下,我希望组件在视图状态中保持其排序顺序,然后在AJAX请求期间提交适当的参数(以便正确定义排序)。我错过了一个参数或什么?还有其他人有这个问题吗?
从表格预期排序时我可以看出它发布了以下选项:
<componentID>_sortDir
<componentID>_sortKey
<componentID>_sorting
<componentID>_updateBody
当我刷新表单时,这不会发生。如果我只刷新表格也不会发生这种情况(我想通过直接更新组件可以解决问题)。有没有办法让表格正确刷新?
答案 0 :(得分: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 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);
}
答案 1 :(得分:5)
首先,PrimeFaces Issue Tracker上有一张打开的门票,针对这个问题,但最近标记为“无法修复”。
尽管如此,我找到了一个很好的解决方法。可以通过在数据表的小部件上调用未记录的JavaScript方法来触发PrimeFaces表的排序。以下可能不适用于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')" />
答案 2 :(得分:3)
编辑:
下面发布的解决方案(LazyTable)适用于使用LazyDataModel支持的p:dataTable。在所需的表上每次更新/刷新后调用Overriden load 方法,并且它正确处理排序。简单的p:dataTable的问题在于它仅在第一次加载时或在单击sort列之后执行预定义排序。这是简单表的正常行为。
那么简单表的可能性是什么:
请勿在更新后对表进行排序,但请删除排序列,以便最终用户不会错过信息。将其添加到更新按钮的动作侦听器或操作方法中:
UIComponent table = FacesContext.getCurrentInstance().getViewRoot().findComponent(":dataTablesForm:dataTableId");
table.setValueExpression("sortBy", null);
通过脚本手动更新表格的排序。这不是最好的解决方案,但是primefaces没有为“求助”表提供任何客户端功能。 基本上你知道一次只能排序一列,而且这个列的.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,排序一些列(保持facelet打开),从另一个.xhtml更新dataTables数据,例如,单击刷新按钮。 dataTable应以正确(先前选择的)排序顺序显示您的添加值 - 更新后执行排序。
希望它有所帮助!
答案 3 :(得分: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很快就会修复它,我会稍后再详细介绍并提供更新。
答案 4 :(得分: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());
}
}
答案 5 :(得分:0)
解决方案是拥有一个会话bean。在这种情况下,p:dataTable刷新表及其条目而不影响排序顺序。如果每行都有一个p: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>
答案 6 :(得分:0)
我和你有同样的问题。我能够使用LazyDataModel解决问题。由于PrimeFaces issue with the row index,我需要添加额外的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
}
答案 7 :(得分: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;
}
}
}
}
}