景色:
<h:form ...
<p:dataTable value="#{myBean.list}" var="data" ...
<p:column ...
<h:commandButton action="#{controller.method(data.id)}" />
</p:column>
</p:dataTable>
</h:form>
コントローラー:
@ApplicationScoped
public class Controller {
public String method(final Long dataId) {
/* Do business */
return URL_WITH_REDIRECT;
}
}
プロデューサー
(ここで@ViewScoped
説明されているように CDI 注釈を使用)
@ApplicationScoped
public class Producer {
@Named @ViewScoped @Producer
public MyBean getMyBean() {
final MyBean bean = new MyBean();
bean.list = new ArrayList<Data>(); // where Data has a Long id field
/* Do business and populate list */
return bean;
}
}
問題とそのシナリオ
GET
ページ- 豆が産まれる
- ビューがレンダリングされます
- ブラウザーに送信された応答
- ボタンをクリックします
- データは
POST
サーバーに送信されます - フェーズ1 ~ 4 は問題なく実行され
@ViewScoped
、期待どおりに Beanを使用します - フェーズ 5:
controller.method
で呼び出され、 1.1data.id
で生成された Bean にアクセスします - メソッドはリダイレクトを返します
String
- !! プロデューサーが再び呼び出されます!! - まだ APPLICATION_INVOCATION フェーズにありますが、実際のメソッド呼び出しの後です
- データは
- ブラウザがリダイレクトを受け取る
GET
次のページ ...
機能する半分「ロバ」ソリューション:
要するに、クリックすると、IDをデータテーブルの外にコピーし、送信ボタンのクリックをトリガーします。
表の列のh:commandButton
内側に次のように追加されました。
onclick="$('input[id*=selectedDataId]').val('#{data.id}'); $('button[id*=callMethod]').trigger('click');"
テーブルの外:
<h:inputHidden id="{selectedDataId}"binding="#{selectedDataId}"/>
<p:commandButton type="submit"
id="callMethod"
label="Hidden button"
action="#{controller.method(selectedDataId.value)}"/>
最終的には機能しますが、最初と基本のアプローチがビュー スコープ Bean を再初期化する原因を突き止めることができませんでした。スタック トレース (以下を参照) を見ると、行を再構築しているように見えます。
質問:
誰かが説明を持っていますか?この問題に関して注意すべき点はありますか?
スタックトレース
ここで:getPipelinecheckSearchResults
テーブルを裏付けるリストを取得するための呼び出しであり、プロデューサーが呼び出されます
私がすでに見たこと:
上記の(1番目の)ソリューションが機能する理由について理解を深めることなく、次の記事/ SOの質問を読みました。
ViewScoped Bean は、dataTable の commandButton をクリックするたびに再作成されます
Bean が @ViewScoped であるにもかかわらず、@PostConstruct コールバックが毎回起動するのはなぜですか? JSF
選択した行をdataTable内のcommandLinkに渡すにはどうすればよいですか?
http://balusc.blogspot.de/2010/06/benefits-and-pitfalls-of-viewscoped.html