【问题标题】:Reordering p: p:dataTable rows containing inputs重新排序 p: p:dataTable 包含输入的行
【发布时间】:2016-02-27 18:27:36
【问题描述】:

一列中有p:dataTablep: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>

支持 bean:

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

并在重新排序后(将第 1 行移至第 3 行):

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

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

【问题讨论】:

  • 调试显示dataList 的旋转发生在decode()decode()APPLY_REQUEST_VALUES 阶段org.primefaces.component.datatable.feature.DraggableRowsFeature。并且输入的设置值稍后发生在UPDATE_MODEL_VALUES 阶段,已经重新排序dataList,这是一个问题。
  • 只是猜测,但尝试在 Data 中实现 equals() 和 hashCode()
  • 我做到了。只是没有显示。它的默认值....

标签: jsf-2 primefaces


【解决方案1】:

第一个解决方案

我找到了解决办法! 它不处理带有process="@none" partialSubmit="true"属性的输入(实际上根本不提交)

所以完整的 p:ajax 组件看起来像 &lt;p:ajax event="rowReorder" listener="#{rowReorder.reorder}" update="dataTable" process="@none" partialSubmit="true"/&gt;


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

理论:

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

DraggableRowsFeature.decode() 中,我们可以看到Collections.rotate() 仅在值为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");
}

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

  1. 不要使用List作为dataTable值
  2. 创建自己的 org.primefaces.component.datatable.feature.DraggableRowsFeatureshouldDecode() 方法中返回 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 阶段向模型和轮换列表提交值。

【讨论】:

  • 我不确定这是不是最好的解决方案,但它确实有效。
  • 如果您之后编辑行,它仍然有效吗?没有错误?
  • 它会起作用,但您需要将之前输入的数据提交给 ViewRoot。例如&lt;p:inputText value="#{row.name}"&gt; &lt;p:ajax process="@this" update="@this"/&gt; &lt;/p:inputText&gt;
  • 选项 2 应该如何工作?除了破解 DataTableRenderer 之外,我没有看到任何插入自定义数据表功能的选项?任何帮助表示赞赏。
  • @lastresort 这是不可能的,因为它没有可扩展的面组件。我没有找到任何方法来注册自定义 DraggableRowsFeature 而不破解 primefaces 源...
【解决方案2】:

秘密是你的数据表的属性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 函数时,值不会改变超过一行。

我等着帮你。

【讨论】:

    【解决方案3】:

    其他简单的解决方案是禁用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>
    

    【讨论】:

      猜你喜欢
      • 2021-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-20
      • 1970-01-01
      • 2021-07-18
      相关资源
      最近更新 更多