わかりにくいタイトルですみません(^^;
JSFで必須バリデーションなどを無視して画面遷移したい場合(戻るボタン、みたいな)、通常はCommandButtonの属性にあるimmediateをtrueにして回避することがあると思います。
自分も今までこれで問題なく進んできたのですが、今日、上手く対応できないケースがありました。
具体的には
- ajaxを利用しているCommandButton
- 同一の画面内で更新
のケースです。画面遷移するようなケースは問題ないのですが、上記は駄目でした。
簡単なサンプル作ったら再現できたので以下に具体例を載せます。
まずは話をわかりやすくするため、普通の例から並べてみます。
入力フォームがあって、入力をキャンセルする
例えば…ですが、何かの入力項目があって、そこに文字を入れたけど、キャンセルして空白にする、みたいなケースです。
イメージは下図のような感じでテキストとボタンがあって
テキストに何か文字を入れます
ボタン押すとクリアされます
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です。
左に必須のテキストが追加された状態でてくるので、先と同じようにテキストに文字入力します。
この状態でキャンセルボタンを押すと…バリデーションエラーになります(わかりにくいですが下図で左のテキストが赤くなってます)。
ここまでは当たり前な流れですね(^^;
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にします。すると
必須のエラーは引っかからなくなった!!!けれども、今度は文字が消されない!!
なんで!ってことで、困ったときの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>
で実行すると
おー、ちゃんと実行された。なんだこれ。
User Guide読むとasyncはajaxのリクエストをキューしないようにするもので、processはビュー全体更新の代わりに部分的に処理する、みたいに書いてありますがイマイチちゃんと理解できてない(^^;
こういう細かい所、JSFやAjaxの関連含めてしっかり理解して使いたいなぁ…と思いながら、ついつい入れてしまいました…。