如何将选定的行传递给dataTable中的commandLink或ui:repeat?

Mic*_*rdt 97 datatable jsf parameter-passing commandlink jsf-2

我在JSF 2应用程序中使用Primefaces.我有一个<p:dataTable>,而不是选择行,我希望用户能够直接对各行执行各种操作.为此,我<p:commandLink>在最后一栏中有几个.

我的问题:如何将行ID传递给命令链接启动的操作,以便我知道要对哪一行进行操作?我尝试使用<f:attribute>:

<p:dataTable value="#{bean.items}" var="item">
    ...
    <p:column>
        <p:commandLink actionListener="#{bean.insert}" value="insert">
            <f:attribute name="id" value="#{item.id}" />
        </p:commandLink>
    </p:column>
</p:dataTable>
Run Code Online (Sandbox Code Playgroud)

但它总是产生0 - 显然在f呈现属性时行变量不可用(当我使用固定值时它可以工作).

有人有替代解决方案吗?

Bal*_*usC 214

至于原因,<f:attribute>它特定于组件本身(在视图构建时填充),而不是迭代行(在视图渲染时填充).

有几种方法可以达到要求.

  1. <f:param>改用.它添加了一个请求参数.

    <h:commandLink action="#{bean.insert}" value="insert">
        <f:param name="id" value="#{item.id}" />
    </h:commandLink>
    
    Run Code Online (Sandbox Code Playgroud)

    如果你的bean是请求作用域,让JSF设置它 @ManagedProperty

    @ManagedProperty(value="#{param.id}")
    private Long id; // +setter
    
    Run Code Online (Sandbox Code Playgroud)

    或者,如果您的bean具有更广泛的范围,或者您想要更精细的验证/转换,请<f:viewParam>在目标视图上使用,另请参阅f:viewParam vs @ManagedProperty:

    <f:viewParam name="id" value="#{bean.id}" required="true" />
    
    Run Code Online (Sandbox Code Playgroud)

    无论哪种方式,这都具有以下优点:对于表单提交,不一定需要保留数据模型(对于您的bean是请求作用域的情况).


  2. <f:setPropertyActionListener>改用.优点是当bean具有比请求范围更广的范围时,这消除了访问请求参数映射的需要.

    <h:commandLink action="#{bean.insert}" value="insert">
        <f:setPropertyActionListener target="#{bean.id}" value="#{item.id}" />
    </h:commandLink>
    
    Run Code Online (Sandbox Code Playgroud)

    结合使用

    private Long id; // +setter
    
    Run Code Online (Sandbox Code Playgroud)

    它将由id行动方法中的财产提供.这只需要为表单提交请求保留datamodel.最好是将bean放在视图范围内@ViewScoped.


  3. 如果您的servletcontainer支持Servlet 3.0/EL 2.2,那么只需将其作为方法参数传递.这还要求为表单提交请求保留datamodel.最好是将bean放在视图范围内@ViewScoped.

    <h:commandLink action="#{bean.insert(item.id)}" value="insert" />
    
    Run Code Online (Sandbox Code Playgroud)

    结合:

    public void insert(Long id) {
        // ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    您甚至可以传递整个项目对象:

    <h:commandLink action="#{bean.insert(item)}" value="insert" />
    
    Run Code Online (Sandbox Code Playgroud)

    有:

    public void insert(Item item) {
        // ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    在Servlet 2.5容器上,如果你提供支持它的EL实现,就像JBoss EL一样,这也是可能的.有关配置详细信息,请参阅此答案.


  4. 将数据表值绑定到DataModel<E>而不是包装项目.

    <h:dataTable value="#{bean.model}" var="item">
    
    Run Code Online (Sandbox Code Playgroud)

    private transient DataModel<Item> model;
    
    public DataModel<Item> getModel() {
        if (model == null) {
            model = new ListDataModel<Item>(items);
        }
        return model;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    (transient当你在视图或会话范围的bean上使用它时,必须在getter中实现它并且懒惰地实例化它,因为DataModel它没有实现Serializable)

    然后,您将能够在DataModel#getRowData()不传递任何内容的情况下访问当前行(JSF根据单击的命令链接/按钮的请求参数名称确定行).

    public void insert() {
        Item item = model.getRowData();
        Long id = item.getId();
        // ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这还要求为表单提交请求保留datamodel.最好是将bean放在视图范围内@ViewScoped.


  5. 您可以使用Application#evaluateExpressionGet()以编程方式评估当前#{item}.

    public void insert() {
        FacesContext context = FacesContext.getCurrentInstance();
        Item item = context.getApplication().evaluateExpressionGet(context, "#{item}", Item.class);
        Long id = item.getId();
        // ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

选择哪种方式取决于功能要求以及这一方面是否为其他目的提供了更多优势.我个人会继续使用#3,或者当你想支持servlet 2.5容器时,#2.

  • 使用"过滤",你的意思是在[这个展示示例](http://www.primefaces.org/showcase/ui/datatableFiltering.jsf)?症状表明过滤器操作仅在客户端进行,并且不维护服务器端的模型.不确定这是否是故意的.您可以随时留下问题报告. (2认同)

Boz*_*zho 11

在JSF 1.2中,这是由<f:setPropertyActionListener>(在命令组件中)完成的.在JSF 2.0(确切地说是EL 2.2,感谢BalusC),可以这样做:action="${filterList.insert(f.id)}

  • 此功能并非特定于JSF 2.0(它本身可以在Servlet 2.5容器中运行),而是特定于EL 2.2(它是Servlet 3.0的一部分). (6认同)

小智 11

在我的视图页面中:

<p:dataTable  ...>
<p:column>
<p:commandLink actionListener="#{inquirySOController.viewDetail}" 
               process="@this" update=":mainform:dialog_content"
           oncomplete="dlg2.show()">
    <h:graphicImage library="images" name="view.png"/>
    <f:param name="trxNo" value="#{item.map['trxNo']}"/>
</p:commandLink>
</p:column>
</p:dataTable>
Run Code Online (Sandbox Code Playgroud)

支持豆

 public void viewDetail(ActionEvent e) {

    String trxNo = getFacesContext().getRequestParameterMap().get("trxNo");

    for (DTO item : list) {
        if (item.get("trxNo").toString().equals(trxNo)) {
            System.out.println(trxNo);
            setSelectedItem(item);
            break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)