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


99

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

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

有人有替代解决方案吗?

Answers:


215

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

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

  1. 如果您的servlet容器至少支持Servlet 3.0 / EL 2.2,则只需将其作为UICommand 组件或AjaxBehavior标签的action / listener方法的参数传递。例如

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

    结合:

     public void insert(Long id) {
         // ...
     }

    这仅需要为表单提交请求保留数据模型。最好的方法是将bean放在视图范围内@ViewScoped

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

     <h:commandLink action="#{bean.insert(item)}" value="insert" />

    与:

     public void insert(Item item) {
         // ...
     }

    在Servlet 2.5容器上,如果您提供支持该功能的EL实现(例如JBoss EL),这也是可能的。有关配置的详细信息,请参见此答案


  2. <f:param>UICommand组件中使用。它添加了一个请求参数。

     <h:commandLink action="#{bean.insert}" value="insert">
         <f:param name="id" value="#{item.id}" />
     </h:commandLink>

    如果您的bean是请求范围的,请让JSF通过以下方式进行设置: @ManagedProperty

     @ManagedProperty(value="#{param.id}")
     private Long id; // +setter

    或者,如果您的bean范围更广,或者您想要更细粒度的验证/转换,请<f:viewParam>在目标视图上使用,另请参见f:viewParam与@ManagedProperty

     <f:viewParam name="id" value="#{bean.id}" required="true" />

    无论哪种方式,这都有一个优点,即不必为表单提交保留数据模型(对于您的bean是请求范围的情况)。


  3. <f:setPropertyActionListener>UICommand组件中使用。优点是,当bean的作用域比请求作用域更广时,这就不需要访问请求参数映射。

     <h:commandLink action="#{bean.insert}" value="insert">
         <f:setPropertyActionListener target="#{bean.id}" value="#{item.id}" />
     </h:commandLink>

    与结合

     private Long id; // +setter

    只能通过id动作方法中的属性来使用。这仅需要为表单提交请求保留数据模型。最好的方法是将bean放在视图范围内@ViewScoped


  4. 将datatable值绑定到DataModel<E>,然后将其包装。

     <h:dataTable value="#{bean.model}" var="item">

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

    transient当您在视图或会话范围的bean上使用它时,由于DataModel没有实现,因此必须在getter中进行创建并延迟实例化它是必需的Serializable

    然后,您DataModel#getRowData()无需进行任何传递就可以访问当前行(JSF根据单击的命令链接/按钮的请求参数名称确定该行)。

     public void insert() {
         Item item = model.getRowData();
         Long id = item.getId();
         // ...
     }

    这还要求为表单提交请求保留数据模型。最好的方法是将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();
         // ...
     }

选择哪种方式取决于功能要求以及一个或另一个是否为其他目的提供更多优势。我个人将继续使用#1,或者当您也想支持Servlet 2.5容器时,使用#2。


1
+1,尽管我更喜欢#2(如果必须支持2.5)。
2011年

感谢您详尽的回答。不幸的是,我不得不报告#1是唯一在过滤后的primefaces数据表中起作用的东西(这正是我需要的方案)。所有其他仅在未过滤的表上工作。不过,与您的回答相比,我认为这更多是素字样的错误。
Michael Borgwardt

Bean请求或视图是作用域范围内的吗?
BalusC

2
使用“已过滤”是指此示例示例中的内容?这些症状表明筛选器操作仅在客户端发生,并且未维护服务器端的模型。不知道这是否是故意的。您可以随时留下问题报告。
BalusC

您的帖子介于我读过的最有用的帖子之间。我使用方法5是因为我被迫使用Servlet 2.5。我现在的问题是,是否可以通过commandLink(如您的示例)使用ajax发送参数?
Aditzu 2014年

11

在JSF 1.2中,这是通过<f:setPropertyActionListener>(在命令组件内)完成的。在JSF 2.0(准确地说是EL 2.2,多亏了BalusC)中,可以这样做:action="${filterList.insert(f.id)}


6
此功能不是特定于JSF 2.0(它本身可以在Servlet 2.5容器中运行),而是特定于EL 2.2(它是Servlet 3.0的一部分)。
BalusC

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>

支持豆

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

-1

多亏Mkyong的这个网站实际上对我们传递参数的唯一解决方案是

<h:commandLink action="#{user.editAction}">
    <f:param name="myId" value="#{param.id}" />
</h:commandLink>

public String editAction() {

  Map<String,String> params = 
            FacesContext.getExternalContext().getRequestParameterMap();
  String idString = params.get("myId");
  long id = Long.parseLong(idString);
  ...
}

从技术上讲,您不能直接传递给方法本身,而可以传递给JSF request parameter map


1
您遇到的问题与此处提出的问题不同。您希望保留来自#{param}映射的请求参数以用于后续请求,而不传递任何参数。您的问题与
答案
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.