web-dev-qa-db-ja.com

commandButton / commandLink / ajaxアクション/リスナーメソッドが呼び出されていない、また入力値が設定/更新されていない

時々、<h:commandLink><h:commandButton>または<f:ajax>を使用するとき、タグに関連したactionactionListenerまたはlistenerメソッドは単に呼び出されていません。または、Beanプロパティが送信されたUIInput値で更新されていません。

考えられる原因と解決策は何ですか?

327
Muhammad Hewedy

前書き

UICommandコンポーネント(<h:commandXxx><p:commandXxx>など)が関連付けられたアクションメソッドの呼び出しに失敗した場合、またはUIInputコンポーネント(<h:inputXxx><p:inputXxxx>など)が送信された値の処理またはモデル値の更新に失敗した場合JSF ajaxリクエストで例外処理 を使用してajax例外ハンドラーを構成した場合 、または以下のcontextパラメーターを設定した場合も、サーバーログ内の検索可能な例外や警告は発生しません。 web.xml

<context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
</context-param>

また、ブラウザのJavaScriptコンソールにgooglableなエラーや警告が表示されず(Chrome/Firefox 23 +/IE 9 +でF12キーを押してWeb開発者用ツールセットを開き、次にConsoleタブを開く)、次に進みます。考えられる原因のリストの下に。

考えられる原因

  1. UICommandおよびUIInputコンポーネントはUIFormコンポーネント内に配置する必要があります。 <h:form>(そしてそれ故、普通のHTMLの<form>ではありません) UICommandコンポーネントにはtype="button"属性も含めることはできません。そうしないと、JavaScriptのonclickにのみ役立つデッドボタンになります。参照 JSF Beanでフォーム入力値を送信してメソッドを呼び出す方法 および <h:commandButton>はポストバックを開始しません

  2. 複数のUIFormコンポーネントを互いに入れ子にすることはできません。これはHTMLでは違法です。ブラウザの動作は規定されていません。インクルードファイルに気をつけろ! UIFormコンポーネントは並行して使用できますが、送信中に互いに処理することはありません。また、「God Form」対パターンにも気を付けるべきです。まったく同じ形式の他の(表示されていない)入力を意図せずに処理/検証しないようにしてください(たとえば、同じ形式の必須入力を持つ隠しダイアログがあるなど)。参照 JSFページで<h:form>を使用する方法シングルフォーム?複数のフォーム?入れ子になったフォーム? .

  3. UIInput値の検証/変換エラーは発生していないはずです。 <h:messages>を使用すると、入力固有の<h:message>コンポーネントによって表示されないメッセージを表示できます。 ajaxリクエストでも更新されるように、<h:messages>id<f:ajax render>に含めることを忘れないでください。 も参照してください。h:messagesは、p:commandButtonが押されたときにメッセージを表示しません

  4. UICommandまたはUIInputコンポーネントが<h:dataTable><ui:repeat>などの反復コンポーネント内に配置されている場合は、フォームsubmit requestの要求値の適用フェーズで、反復コンポーネントとまったく同じvalueを確実に保持する必要があります。 JSFはそれを繰り返してクリックされたリンク/ボタンを見つけ、入力値を送信します。 Beanをビュースコープに配置するか、データモデルをBeanの@PostConstructにロードしたことを確認してください(したがってgetterメソッドには含まれていません)。また、 を参照してください。h:dataTable については、データベースからモデルをいつどのようにロードする必要があります。

  5. UICommandまたはUIInputコンポーネントが<ui:include src="#{bean.include}">などの動的ソースに含まれている場合は、フォーム送信要求のビュー構築時に、まったく同じ#{bean.include}値が保持されるようにする必要があります。 JSFはコンポーネントツリーの構築中にそれを再実行します。 Beanをビュースコープに配置するか、データモデルをBeanの@PostConstructにロードしたことを確認してください(したがってgetterメソッドには含まれていません)。ナビゲーションメニューで動的インクルードコンテンツをajax-refreshする方法は? もご覧ください。 (JSF SPA) .

  6. コンポーネントおよびそのすべての親のrendered属性、および任意の親のtest属性<c:if>/<c:when>は、フォーム送信要求の要求値適用フェーズ中にfalseに評価されるべきではありません。 JSFは改ざんやハッキングされたリクエストに対する保護策の一部としてそれを再確認します。 @ViewScopedビーンに条件に責任がある変数を格納するか、@PostConstructビーンの@RequestScopedに条件を適切に事前初期化していることを確かめることはそれを修正するべきです。同じことがコンポーネントのdisabled属性にも当てはまります。これは、要求値の適用フェーズ中にtrueに評価されるべきではありません。参照 JSF CommandButtonアクションが呼び出されない および 条件付きでレンダリングされたコンポーネントのフォーム送信が処理されない

  7. onclickコンポーネントのUICommand属性およびonsubmitコンポーネントのUIForm属性は、falseを返したり、JavaScriptエラーを引き起こしたりするべきではありません。 <h:commandLink>または<f:ajax>の場合も、ブラウザのJSコンソールにはJSエラーが表示されないはずです。通常正確なエラーメッセージをグーグルすることは既にあなたに答えを与えるでしょう。 PrimeFacesにjQueryを追加すると、すべての場所でUncaught TypeErrorが発生します

  8. もしあなたがJSF 2.x <f:ajax>経由でAjaxを使っているなら、またはPrimeFaces <p:commandXxx>は、マスターテンプレートに<h:head>ではなく<head>があることを確認してください。そうでなければ、JSFはAjax関数を含む必要なJavaScriptファイルを自動インクルードすることができません。これにより、ブラウザのJSコンソールで "mojarraが定義されていません"または "PrimeFacesが定義されていません"などのJavaScriptエラーが発生します。 も参照してください。h:commandLink actionlistenerは、f:ajaxおよびui:repeat と共に使用した場合は呼び出されません。

  9. Ajaxを使用している場合は、目的のUIInputおよびUICommandコンポーネントが<f:ajax execute>でカバーされていることを確認してください。 <p:commandXxx process>、それ以外の場合は実行または処理されません。参照 <f:ajax>を<h:commandButton> および に追加したときに送信されたフォーム値がモデル内で更新されないPrimeFcesのprocess/updateおよびJSFについて:ajax実行/レンダリング属性 .

  10. UICommandボタンを持つ<h:form>の親が、同じページ内の別のフォームからのajaxリクエストによって事前にレンダリング/更新されている場合、最初のアクションは常に失敗します。 2番目以降のアクションは機能します。これは、 JSF仕様の問題790 として報告され、現在JSF 2.3で修正される予定のビューステート処理のバグが原因です。古いバージョンのJSFでは、<h:form>render<f:ajax>のIDを明示的に指定する必要があります。 も参照してください。h:commandButton/h:commandLinkは1回目のクリックでは機能せず、2回目のクリックでのみ機能します

  11. ファイルのアップロードをサポートするために<h:form>enctype="multipart/form-data"が設定されている場合は、少なくともJSF 2.2を使用していること、またはマルチパート/フォームデータ要求の解析を担当するサーブレットフィルタが正しく設定されていることを確認する必要があります。 FacesServletはリクエストパラメータをまったく取得しないため、リクエスト値を適用できません。このようなフィルタの設定方法は、使用されているファイルアップロードコンポーネントによって異なります。 Tomahawk <t:inputFileUpload>の場合、この回答をチェック 、PrimeFacesの<p:fileUpload>の場合、この回答をチェック します 。または、実際にファイルをまったくアップロードしていない場合は、属性をすべて削除します。

  12. ActionEventactionListener引数がjavax.faces.event.ActionEventであり、したがってJava.awt.event.ActionEventではないことを確認してください。これは、ほとんどのIDEが1番目のオートコンプリートオプションとして推奨するものです。 actionListener="#{bean.method}"を使用している場合も、引数がないことは間違っています。メソッドに引数が必要ない場合はactionListener="#{bean.method()}"を使用してください。あるいは、実際にはactionの代わりにactionListenerを使いたいと思うかもしれません。 actionとactionListenerの違い も参照してください。

  13. 要求 - 応答チェーン内のPhaseListenerまたはEventListenerが、アクション呼び出しフェーズをスキップするようにJSFライフサイクルを変更していないことを確認します。たとえば、FacesContext#renderResponse()またはFacesContext#responseComplete()を呼び出します。

  14. 同じ要求 - 応答チェーン内のFilterまたはServletが、何らかの理由でFacesServletの要求をブロックしていないことを確認してください。

  15. フレームワークのバグたとえば、defaultLabel属性を持つrich:calendar UI要素(または場合によってはrich:placeholderサブ要素)を使用すると、RichFacesには「 変換エラー 」が表示されます。このバグは、カレンダ日付に値が設定されていないときにBeanメソッドが呼び出されないようにします。フレームワークのバグのトレースは、簡単な実用的な例から始めて、バグが見つかるまでページを元に戻すことによって実現できます。

  16. PrimeFaces <p:dialog>または<p:overlayPanel>を使用している場合は、それらが独自の<h:form>を持っていることを確認してください。なぜなら、これらのコンポーネントはデフォルトでJavaScriptのHTMLの末尾に移動した<body>です。そのため、元々<form>の内側に座っていたのであれば、もはや<form>の中に座っていないでしょう。 も参照してください。p:commandbuttonアクションはp:dialog内では機能しません

デバッグのヒント

それでも動けない場合は、デバッグする時が来ました。クライアントサイドでは、WebブラウザでF12キーを押してWeb開発者ツールセットを開きます。 Consoleタブをクリックして、JavaScriptコンソールを見てください。 JavaScriptのエラーがないことを確認してください。下のスクリーンショットはChromeからの例です。これは、<f:ajax>が宣言されていないのに<h:head>対応ボタンを送信するケースを示しています(上記のポイント7で説明)。

js console

HTTPトラフィックモニタを表示するには、Networkタブをクリックします。フォームを送信して、要求ヘッダーとフォームデータ、および応答本文が予想どおりかどうかを調べます。以下のスクリーンショットはChromeからの例で、単一の<h:inputText>と単一の<h:commandButton>および<f:ajax execute="@form" render="@form">を含む単純なフォームのajax送信が成功したことを示しています。

network monitor

(警告:本番環境から上記のようなHTTPリクエストヘッダからスクリーンショットを投稿するときは、セッションハイジャック攻撃を避けるためにスクリーンショットのセッションクッキーをスクランブル/難読化してください。)

サーバー側で、サーバーがデバッグモードで起動されていることを確認します。フォーム送信の処理中に呼び出されることが予想される、関心のあるJSFコンポーネントのメソッドにデバッグブレークポイントを設定します。例えば。 UICommandコンポーネントの場合は、 UICommand#queueEvent() となり、UIInputコンポーネントの場合は、 UIInput#validate() となります。コードの実行を一通り行い、フローと変数が予想どおりであるかどうかを調べます。下のスクリーンショットはEclipseのデバッガの例です。

debug server

656
BalusC

あなたのh:commandLinkh:dataTableの内側にある場合、h:commandLinkが機能しないかもしれないもう一つの理由があります:

h:dataTableにバインドされている基礎となるデータソースは、リンクがクリックされたときにトリガーされる2番目のJSFライフサイクルでも利用可能でなければなりません。

そのため、基になるデータソースがスコープ指定のリクエストである場合、h:commandLinkは機能しません。

52
jbandi

私の答えは100%当てはまるわけではありませんが、ほとんどの検索エンジンはこれを最初のヒットとして見つけていますが、それでも投稿することにしました。

PrimeFaces(またはそれに類するAPI)のp:commandButtonまたはp:commandLinkを使用している場合は、process="@this"をコマンドコンポーネントに明示的に追加するのを忘れている可能性があります。

『PrimeFacesユーザガイド』のセクション3.18に記載されているように、processupdateのデフォルトはどちらも@formであり、プレーンJSFのf:ajaxまたはRichFaces(それぞれexecute="@this"およびrender="@none")から予想されるデフォルトとはまったく反対です。

調べるのにちょうど私の時間がかかりました。 (...そして、JSFとは異なるデフォルトを使用するのはどちらかというと不明瞭です!)

26
Kawu

Primefacesのp:commandButtonに関するもう1つのことを述べます。

サーバーで実行する必要があるアクションにp:commandButtonを使用する場合は、type="button"を使用できません。 ボタンを押す これは、サーバーへのajax/non -jaxリクエストを引き起こさずにカスタムjavascriptを実行するために使用されます。

この目的のために、type属性を省略すること(デフォルト値は"submit")または明示的にtype="submit"を使用することができます。

これが誰かに役立つことを願っています!

9
akelec

私は最近、UICommandがIBM Extended Faces Componentsを使用してJSF 1.2アプリケーションを呼び出さないという問題に遭遇しました。

データテーブルの行にコマンドボタンがあり(拡張バージョンなので<hx:datatable>)、UICommandはテーブルの特定の行から起動しません(起動しない行はデフォルトの行表示サイズより大きい行でした)。

表示する行数を選択するためのドロップダウンコンポーネントがありました。このフィールドの背後にある値はRequestScopeにありました。テーブル自体を裏付けるデータは一種のViewScopeにありました(実際には、一時的にSessionScopeに入っていました)。

どの値がデータテーブルのrows属性にもバインドされているかによってコントロールを介して行の表示が増えた場合、この変更の結果として表示される行はどれもクリック時にUICommandを起動できません。

この属性をテーブルデータ自体と同じスコープに配置することで問題は解決しました。

これは上記のBalusC#4で示唆されていると思いますが、テーブルの値はViewまたはSessionスコープである必要があるだけでなく、そのテーブルに表示する行数を制御する属性も必要です。

3
Brent C

私自身がこの問題に立ち往生しており、この問題のもう1つの原因を見つけました。バッキングBeanに* .xhtmlで使用されているプロパティの設定メソッドがない場合は、単純にアクションは呼び出されません。

3
Syed Mehtab

私もこの問題を抱えていて、ブラウザのWebコンソールを開いた後に、根本的な原因に集中し始めました。それまでは、(<p:messages>でも)エラーメッセージを受け取ることができませんでした。 Webコンソールは<h:commandButton type="submit" action="#{myBean.submit}">から戻ってくるHTTP 405ステータスコードを示しました。

私の場合は、Auth0を介したOAuth認証を提供するVanilla HttpServletとJSFファセットおよびBeanを組み合わせて、私のアプリケーションビューとビジネスロジックを実行しています。

Web.xmlをリファクタリングし、middle-man-servletを削除すると、それは「魔法のように」機能しました。

結論として、問題は、middle-man-servletがRequestDispatcher.forward(...)を使用してHttpServlet環境からJSF環境にリダイレクトしていたのに対し、それ以前に呼び出されていたサーブレットはHttpServletResponse.sendRedirect(..)でリダイレクトされていたことです。 。).

基本的に、sendRedirect()を使用するとJSFの「コンテナ」が制御を取得できましたが、RequestDispatcher.forward()は明らかにそうではありませんでした。

わからないのは、なぜfaceletがbeanプロパティにアクセスできたが設定できなかったのか、そしてこれが明らかにservletsとJSFの混在をなくすことを叫んでいることです。テーブルバンギング。

2
Brooks

もう1つの可能性:症状が最初の呼び出しは機能するがそれ以降の機能が機能しないことである場合、ここで詳述するように、JSF 2.2でPrimeFaces 3.xを使用している可能性があります。 ViewStateは送信されません

0
Dave Mulligan

richfacesdatatable内の<h:commandLink>のアクションが起動を拒否したという問題をデバッグするのはとても楽しいことでした。このテーブルは以前は動作していましたが、明らかな理由もなく停止しました。私のrich:datatableが間違ったrowKeyConverterを使っていたことを知るためだけに、私は何の問題もありませんでした。これは私の<h:commandLink>アクションが呼ばれるのを防ぎました。

0
Mustafa