選択した行を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属性がレンダリングされるときは、行変数は使用できないようです(固定値を使用すると機能します)。

誰かが代替ソリューションを持っていますか?

回答:


215

原因については、<f:attribute>(ビューの作成時に入力される)コンポーネント自体に固有であり、(ビューのレンダリング時に入力される)反復行に固有ではありません。

要件を達成するにはいくつかの方法があります。

  1. servletcontainerが最小のServlet 3.0 / EL 2.2をサポートしている場合は、UICommand コンポーネントまたはAjaxBehaviorタグのアクション/リスナーメソッドの引数としてそれを渡します。例えば

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

    と組み合わせて:

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

    これは、データモデルがフォーム送信リクエストのために保存されていることのみを必要とします。最善の方法は、Beanをビュースコープに配置することです。@ViewScoped

    アイテムオブジェクト全体を渡すこともできます。

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

    と:

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

    サーブレット2.5コンテナでは、JBoss ELのように、これをサポートする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. DataModel<E>代わりにdatatable値をバインドし、次にアイテムをラップします。

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

    (を実装しtransientDataModelいないため、ビューまたはセッションスコープBeanでこれを使用している場合、それを作成し、ゲッターで遅延してインスタンス化することが必須です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に進むか、サーブレット2.5コンテナーもサポートする場合は#2に進みます。


1
+1、ただし私の好みは#2です(2.5をサポートする必要がある場合)。
Bozho

徹底的な答えをありがとう。残念ながら、私は#1がフィルター処理されたprimefacesデータテーブルで機能した唯一のものであることを報告する必要があります(これはまさに私が必要とするシナリオです)。他のすべてのユーザーは、フィルタリングされていないテーブルでのみ作業しました。私はこれをあなたの答えよりもprimefacesのバグと考えています。
マイケルボルグワート

Beanリクエストまたはビューのスコープはありますか?
BalusC、2011

2
「フィルタリングされた」とは、このショーケースの例のようにですか?症状は、フィルターアクションがクライアント側でのみ行われ、サーバー側のモデルが維持されないことを示しています。これが意図的なものかどうかはわかりません。問題レポートはいつでも残すことができます。
BalusC 2011

あなたの投稿は、私が今まで読んだ中で最も役立つ投稿の間にあります。サーブレット2.5を使用する必要があるため、方法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、2011

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}任意のパラメーターを渡すのではなく、後続の要求のためにマップからの要求パラメーターを保持したい。Q&Aは、stackoverflow.com
questions / 17734230
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.