Challenge Engineer Life !

エンジニア人生を楽しみたい!仕事や趣味で学んだ技術的なことを書いていくブログです。

PrimeFacesのボタンでAjaxとimmediateが絡んでキャンセルボタンが上手く動作しない時

わかりにくいタイトルですみません(^^;

JSFで必須バリデーションなどを無視して画面遷移したい場合(戻るボタン、みたいな)、通常はCommandButtonの属性にあるimmediateをtrueにして回避することがあると思います。

自分も今までこれで問題なく進んできたのですが、今日、上手く対応できないケースがありました。
具体的には

  • ajaxを利用しているCommandButton
  • 同一の画面内で更新

のケースです。画面遷移するようなケースは問題ないのですが、上記は駄目でした。

簡単なサンプル作ったら再現できたので以下に具体例を載せます。
まずは話をわかりやすくするため、普通の例から並べてみます。

入力フォームがあって、入力をキャンセルする

例えば…ですが、何かの入力項目があって、そこに文字を入れたけど、キャンセルして空白にする、みたいなケースです。

イメージは下図のような感じでテキストとボタンがあって
f:id:kikutaro777:20130510192421j:plain

テキストに何か文字を入れます
f:id:kikutaro777:20130510192439j:plain

ボタン押すとクリアされます
f:id:kikutaro777:20130510192504j:plain

JSFは以下です。actionListenerでBackingBeanのcancelメソッドを実行してますが、この中身は単にinputValueにnullを入れてるだけです。

<h:form id="frm">
    <p:inputText id="txtInput" value="#{requiredCancelBean.inputValue}" />
    <p:commandButton id="btnCancel" value="Cancel"
                     actionListener="#{requiredCancelBean.cancel()}"
                     update="@form" />
</h:form>

これはシンプルな例なので問題ないです。続けて。

必須項目が存在した場合

もう1つテキストを加えて、それを必須とします。required = trueです。

左に必須のテキストが追加された状態でてくるので、先と同じようにテキストに文字入力します。
f:id:kikutaro777:20130510192640j:plain

この状態でキャンセルボタンを押すと…バリデーションエラーになります(わかりにくいですが下図で左のテキストが赤くなってます)。
f:id:kikutaro777:20130510192711j:plain

ここまでは当たり前な流れですね(^^;

JSFは以下。

<h:form id="frm">
    <!-- 必須項目追加 -->
    <p:inputText id="txtRequiredInput" required="true" value="#{requiredCancelBean.inputReqValue}" />

    <p:inputText id="txtInput" value="#{requiredCancelBean.inputValue}" />
    <p:commandButton id="btnCancel" value="Cancel"
                     actionListener="#{requiredCancelBean.cancel()}"
                     update="@form" />
</h:form>
immediateの登場

で、immediateフラグをtrueにします。すると

f:id:kikutaro777:20130510193715j:plain

f:id:kikutaro777:20130510193725j:plain

必須のエラーは引っかからなくなった!!!けれども、今度は文字が消されない!!

なんで!ってことで、困ったときのstackoverflowへ…。

ちなみに今のjsfは以下です。

<h:form id="frm">
    <!-- 必須項目追加 -->
    <p:inputText id="txtRequiredInput" required="true" value="#{requiredCancelBean.inputReqValue}" />

    <p:inputText id="txtInput" value="#{requiredCancelBean.inputValue}" />
    <p:commandButton id="btnCancel" value="Cancel"
                     actionListener="#{requiredCancelBean.cancel()}"
                     update="@form" 
                     immediate="true"/>
</h:form>
asyncとprocess属性

StackOverflowにやはり同じようなQAがありました。

JSF immediate=“true” for cancel button doesn't work

immediateは「戻る」ボタンみたいに、ビューが変わるのには良いですが、同一のビュー、かつajaxを利用した場合にはイマイチ問題があるようです。ほぉ…。

で、サンプルにあったのはasyncをtrueにして、processに@thisを指定するというもの。

先にJSFに追加してみました。

<h:form id="frm">
    <!-- 必須項目追加 -->
    <p:inputText id="txtRequiredInput" required="true" value="#{requiredCancelBean.inputReqValue}" />

    <p:inputText id="txtInput" value="#{requiredCancelBean.inputValue}" />
    <p:commandButton id="btnCancel" value="Cancel"
                     actionListener="#{requiredCancelBean.cancel()}"
                     update="@form" 
                     immediate="true"
                     async="true"
                     process="@this"/>
</h:form>

で実行すると

f:id:kikutaro777:20130510194020j:plain

f:id:kikutaro777:20130510194025j:plain

おー、ちゃんと実行された。なんだこれ。
User Guide読むとasyncはajaxのリクエストをキューしないようにするもので、processはビュー全体更新の代わりに部分的に処理する、みたいに書いてありますがイマイチちゃんと理解できてない(^^;

こういう細かい所、JSFAjaxの関連含めてしっかり理解して使いたいなぁ…と思いながら、ついつい入れてしまいました…。

にほんブログ村 IT技術ブログへ
にほんブログ村 にほんブログ村 IT技術ブログ Javaへ
にほんブログ村