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

发布于 2024-10-17 20:46:01 字数 668 浏览 1 评论 0原文

我在 JSF 2 应用程序中使用 Primefaces。我有一个 ,我希望用户能够直接对各个行执行各种操作,而不是选择行。为此,我在最后一列中有几个

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

<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 不可用(当我使用固定值)。

有人有替代解决方案吗?

I'm using Primefaces in a JSF 2 application. I have a <p:dataTable>, and instead of selecting rows, I want the user to be able to directly execute various actions on individual rows. For that, I have several <p:commandLink>s in the last column.

My problem: how can I pass a row ID to the action started by the command link so that I know which row to act on? I tried using an <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>

But it always yields 0 - apparently the row variable f is not available when the attribute is rendered (it works when I use a fixed value).

Anyone has an alternative solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

天邊彩虹 2024-10-24 20:46:01

至于原因, 特定于组件本身(在视图构建时间期间填充),而不是迭代行(在视图渲染时间期间填充)。

有多种方法可以实现该要求。

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

     
    

    结合:

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

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

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

     
    

    与:

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

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

    <小时>

  2. 使用UICommand 组件中。它添加了一个请求参数。

     
         
     
    

    如果您的 bean 是请求范围的,请让 JSF 通过 @ManagedProperty

     @ManagedProperty(value="#{param.id}")
     私人长ID; // +设置器
    

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

     
    

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

    <小时>

  3. 使用UICommand 组件中。优点是,当 bean 的范围比请求范围更广时,这就不需要访问请求参数映射。

     
         
     
    

    结合

     私有长 ID; // +设置器
    

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

    <小时>

  4. 将数据表值绑定到 DataModel< ;E> 相反,它依次包装项目。

     
    

     私有瞬态 DataModel;模型;
    
     公共数据模型获取模型(){
         如果(模型==空){
             模型 = new ListDataModel(items);
         }
         返回模型;
     }
    

    (当您在视图或会话作用域 bean 上使用它时,必须使其暂时并在 getter 中延迟实例化它,因为 DataModel 不会” t 实现可序列化

    然后您将能够通过 DataModel#getRowData() 不传递任何内容(JSF 根据单击的命令链接/按钮的请求参数名称确定行)。

     public void insert() {
         项目项 = model.getRowData();
         长 id = item.getId();
         // ...
     }
    

    这还要求为表单提交请求保留数据模型。最好的办法是通过@ViewScoped将bean放入视图范围内。

    <小时>

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

     public void insert() {
         FacesContext 上下文 = FacesContext.getCurrentInstance();
         Item item = context.getApplication().evaluateExpressionGet(context, "#{item}", Item.class);
         长 id = item.getId();
         // ...
     }
    

    <小时>

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

As to the cause, the <f:attribute> is specific to the component itself (populated during view build time), not to the iterated row (populated during view render time).

There are several ways to achieve the requirement.

  1. If your servletcontainer supports a minimum of Servlet 3.0 / EL 2.2, then just pass it as an argument of action/listener method of UICommand component or AjaxBehavior tag. E.g.

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

    In combination with:

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

    This only requires that the datamodel is preserved for the form submit request. Best is to put the bean in the view scope by @ViewScoped.

    You can even pass the entire item object:

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

    with:

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

    On Servlet 2.5 containers, this is also possible if you supply an EL implementation which supports this, like as JBoss EL. For configuration detail, see this answer.


  2. Use <f:param> in UICommand component. It adds a request parameter.

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

    If your bean is request scoped, let JSF set it by @ManagedProperty

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

    Or if your bean has a broader scope or if you want more fine grained validation/conversion, use <f:viewParam> on the target view, see also f:viewParam vs @ManagedProperty:

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

    Either way, this has the advantage that the datamodel doesn't necessarily need to be preserved for the form submit (for the case that your bean is request scoped).


  3. Use <f:setPropertyActionListener> in UICommand component. The advantage is that this removes the need for accessing the request parameter map when the bean has a broader scope than the request scope.

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

    In combination with

     private Long id; // +setter
    

    It'll be just available by property id in action method. This only requires that the datamodel is preserved for the form submit request. Best is to put the bean in the view scope by @ViewScoped.


  4. Bind the datatable value to DataModel<E> instead which in turn wraps the items.

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

    with

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

    (making it transient and lazily instantiating it in the getter is mandatory when you're using this on a view or session scoped bean since DataModel doesn't implement Serializable)

    Then you'll be able to access the current row by DataModel#getRowData() without passing anything around (JSF determines the row based on the request parameter name of the clicked command link/button).

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

    This also requires that the datamodel is preserved for the form submit request. Best is to put the bean in the view scope by @ViewScoped.


  5. Use Application#evaluateExpressionGet() to programmatically evaluate the current #{item}.

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

Which way to choose depends on the functional requirements and whether the one or the other offers more advantages for other purposes. I personally would go ahead with #1 or, when you'd like to support servlet 2.5 containers as well, with #2.

缘字诀 2024-10-24 20:46:01

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

In JSF 1.2 this was done by <f:setPropertyActionListener> (within the command component). In JSF 2.0 (EL 2.2 to be precise, thanks to BalusC) it's possible to do it like this: action="${filterList.insert(f.id)}

幻梦 2024-10-24 20:46:01

在我的视图页面中:

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

backing bean

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

In my view page:

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

backing bean

 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;
        }
    }
}
糖粟与秋泊 2024-10-24 20:46:01

感谢这个网站作者: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 请求参数地图

Thanks to this site by Mkyong, the only solution that actually worked for us to pass a parameter was this

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

with

public String editAction() {

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

Technically, that you cannot pass to the method itself directly, but to the JSF request parameter map.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文