重新排序 p: p:dataTable 包含输入的行

问题描述 投票:0回答:4

一栏中有

p:dataTable
p:inputText

<h:form id="form">
    <p:dataTable id="dataTable" value="#{rowReorder.dataList}" 
                 var="row" draggableRows="true" rowKey="#{row.id}">
        <p:ajax event="rowReorder" listener="#{rowReorder.reorder}" update="dataTable"/>

        <p:column>
            <f:facet name="header">
                <p:commandButton value="Add" actionListener="#{rowReorder.addData}" 
                                 update="dataTable" process="dataTable"/>
            </f:facet>
            <p:outputLabel value="#{row.id}"/>
        </p:column>
        <p:column>
            <p:inputText value="#{row.name}"/>
        </p:column>
    </p:dataTable>
</h:form>

支撑豆:

import org.omnifaces.cdi.ViewScoped;
import org.primefaces.event.ReorderEvent;
import javax.inject.Named;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;

@Named("rowReorder")
@ViewScoped
public class RowReorder implements Serializable {

    private List<Data> dataList = new LinkedList<>();

    public void addData() {
        Data data = new Data();
        data.setId(dataList.size() + 1);
        data.setName("Data " + data.getId());
        dataList.add(data);
    }

    public void reorder(ReorderEvent event) {

    }

    /**
     * Getters, Setters
     */

    public List<Data> getDataList() {
        return dataList;
    }
}

数据类:

public class Data implements Serializable {

    private Integer id;
    private String name;

    /**
     * Getters, Setters
     */

}

重新排序前的示例数据表:

--------------
|id |  name  |
--------------
| 1 | Data 1 |
| 2 | Data 2 |
| 3 | Data 3 |
| 4 | Data 4 |
--------------

重新排序后(将第一行移动到第三行):

--------------
|id |  name  |
--------------
| 2 | Data 1 |
| 3 | Data 2 |
| 1 | Data 3 |
| 4 | Data 4 |
--------------

我知道发生这种情况是因为在

p:inputText
阶段设置来自
UPDATE_MODEL
的数据。我尝试通过在
process="@none"
组件中指定
p:ajax
来阻止处理输入字段,但它不起作用。您知道如何与
draggableRows
p:inputText
交朋友吗?

jsf-2 primefaces
4个回答
11
投票

第一个解决方案

我找到了解决办法! 它不处理具有属性的输入(实际上根本不提交)

process="@none" partialSubmit="true"

完整的 p:ajax 组件看起来像

<p:ajax event="rowReorder" listener="#{rowReorder.reorder}" update="dataTable" process="@none" partialSubmit="true"/>


第二种方案(如果需要提交数据)

理论:

让我们看看拖动行时发生了什么? 我们有ajax请求强制

process="form:dataTable"
。在 APPLY_REQUEST_VALUES 阶段,
DataTableRenderer
尝试调用
DraggableRowsFeature
的解码,进而旋转列表元素(指定为 dataTable 的 value 属性的列表)。因此,在 UPDATE_MODEL_VALUES 阶段,我们有一个旋转列表和输入组件,它们想要将它们的值提交到
name
对象的
Data
字段。但请求参数在输入 id 中仍然包含旧的行索引:它们是
form:dataTable:1:name = Data 2
form:dataTable:2:name = Data 3
form:dataTable:0:name = Data 1
(我添加了 3 行,并将第一行移至最后一行)。所以在这里我们得到了我们得到的。这样,如果我们需要在正确的位置提交数据,我们必须在 UPDATE_MODEL_VALUES 完成之前防止列表旋转, 并稍后在 INVOKE_APPLICATION 阶段执行此轮换,并在该 ajax 请求上呈现 dataTable:

DraggableRowsFeature.decode()
中我们可以看到
Collections.rotate()
仅当 value 是 List 的实例时才会被调用。

    if (value instanceof List) {
        List list = (List) value;

        if(toIndex >= fromIndex) {
            Collections.rotate(list.subList(fromIndex, toIndex + 1), -1);
        }
        else {
            Collections.rotate(list.subList(toIndex, fromIndex + 1), 1);
        }            
    } 
    else {
        LOGGER.info("Row reordering is only available for list backed datatables, use rowReorder ajax behavior with listener for manual handling of model update.");
    }     

还有

DraggableRowsFeature.shouldDecode()
方法。

public boolean shouldDecode(FacesContext context, DataTable table) {
    return context.getExternalContext().getRequestParameterMap().containsKey(table.getClientId(context) + "_rowreorder");
}

所以这里我们有两种可能性来防止数据源旋转:

  1. 不要使用
    List
    作为数据表值
  2. 创建自己的
    org.primefaces.component.datatable.feature.DraggableRowsFeature
    shouldDecode()
    方法中返回 false。

练习:

我像这样修改了bean文件:

@Named("rowReorder")
@ViewScoped
public class RowReorder implements Serializable {

    private static final Logger log = LoggerFactory.getLogger(RowReorder.class);
    private Set<Data> dataList = new LinkedHashSet<>();


    public void addData() {
        Data data = new Data();
        data.setId(dataList.size() + 1);
        data.setName("Data " + data.getId());
        dataList.add(data);
        log.warn("{} {}", Integer.toHexString(data.hashCode()), data.getId());
    }

    public void removeData(Data data) {
        dataList.remove(data);
    }

    public void reorder(ReorderEvent event) {
        List<Data> list = new LinkedList<>(dataList);

        int fromIndex = event.getFromIndex();
        int toIndex = event.getToIndex();
        if(toIndex >= fromIndex) {
            Collections.rotate(list.subList(fromIndex, toIndex + 1), -1);
        }
        else {
            Collections.rotate(list.subList(toIndex, fromIndex + 1), 1);
        }
        dataList.clear();
        dataList.addAll(list);
    }

    /**
     * Getters, Setters
     */

    public Set<Data> getDataList() {
        return dataList;
    }
}

现在它首先将值提交到模型并在 INVOKE_APPLICATION 阶段旋转列表。


3
投票

秘密是你的数据表的属性

rowStatePreserved
,添加它:

rowStatePreserved =“true”

 <p:dataTable id="dataTable" value="#{rowReorder.dataList}" 
              var="row" draggableRows="true" rowKey="#{row.id}" 
              rowStatePreserved="true">

并将此代码保留为:

<p:ajax event="rowReorder" listener="#{rowReorder.reorder}" update="dataTable" process="@this"/>

在我的例子中,我在数据表列中使用了一个组合框,并且在添加此属性后,当我使用draggableRows函数时,该值不会将超过一行更改为另一行。

我等着帮你。


0
投票

其他简单的解决方案是在

rowReorder
开始时禁用输入:

<p:ajax event="rowReorder"
        onstart="$(':input', PrimeFaces.escapeClientId('#{component.clientId}')).prop('disabled',true)"
        update="@this"/>

注意

#{component.clientId}
将返回数据表的客户端ID。

为了避免丢失数据,您可以 Ajaxify 输入:

<p:column headerText="#{msg.value}">
  <p:inputText value="#{item.value}">
    <p:ajax/>
  </p:inputText>
</p:column>

0
投票

我在使用 Primefaces 12 时遇到了同样的问题。

可悲的是,上面的解决方案对我不起作用,所以我必须寻找另一个选择:

Primefaces 12 在 p:datatable 元素上提供了属性draggableRowsFunction。 如果设置,antonu17 在他的第二个解决方案中描述的默认行为将被禁用。 (参见 org.primefaces.component.datatable.feature.DraggableRowsFeature.decode(...))

这意味着提交正常处理,包括 UPDATE_MODEL_VALUES-Phase 中的正确模型更新。之后,您可以使用 ajax 事件“rowReorder”和侦听器方法来获取带有 from/to 索引的 ReorderEvent-Object 并自行移动列表中的顺序。

这对我有用。

(Primefaces 7 与 antonu17 的第一个解决方案配合良好)

© www.soinside.com 2019 - 2024. All rights reserved.