同じビューツリーにあるコンポーネントのIDを繰り返すことはできません。
ある条件で別のページが含まれているページがあります。
<h:panelGroup rendered="#{bean.insertMode == 'SINGLE'}">
<ui:include src="_single.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{bean.insertMode == 'DOUBLE'}">
<ui:include src="_double.xhtml" />
</h:panelGroup>
現在、これらのページには、「ほぼ」同じコンポーネント階層(コンプレックス)があり、異なるアクションの動作(メソッド呼び出しだけでなく、ビューも)があります。次に例を示します。
_ single.xhtml
<p:inputText id="fieldID" value="#{bean.value}" />
<p:commandLink actionListener="#{bean.singleAction()}" />
_ double.xhtml
<p:inputText id="fieldID" value="#{bean.value}" />
<p:commandLink actionListener="#{bean.doubleAction()}" />
私の小さな例はうまく機能し、想定どおりにレンダリングされますが、
Java.lang.IllegalStateException: Component ID fieldID has already been found in the view.
JSFはページが含まれていない場合でもページ全体を処理することを知っているため、この例外が発生します。
インクルードページ内のコンポーネントのIDを変更せずにこれを解決するスマートな方法(ただし、機能しますが、例外は煩わしく、何か問題があるようです)。
マスターページもこれらのインクルード内のこれらのコンポーネントを参照しているので、formId:fieldIDのような異なるフルIDを持つように、ページのそれぞれを異なるIDのコンテナーコンポーネントでラップしないでください!
重複するコンポーネントIDエラーは、両方がJSFコンポーネントツリーに物理的に含まれるために発生します。 <h:panelGroup rendered="false">
は、JSFコンポーネントツリーに表示されるのを防ぎませんが、HTML出力を生成するのを防ぎます。
HTML出力を条件付きでレンダリングする代わりに、JSFコンポーネントツリーで条件付きでビルドする必要があります。 JSTLはビューのビルド時に実行されるため、この点で非常に役立ちます。
<c:if test="#{bean.insertMode eq 'SINGLE'}">
<ui:include src="_single.xhtml" />
</c:if>
<c:if test="#{bean.insertMode eq 'DOUBLE'}">
<ui:include src="_double.xhtml" />
</c:if>
Mojarraを使用している場合は、少なくともバージョン2.1.18以降を使用する必要があります。そうでない場合、ビュースコープBeanはリクエストスコープBeanのように動作します。
別の方法は、src
属性でEL条件演算子を使用することです(<ui:include>
自体は、ビューのビルド時にもタグハンドラーとして実行されます):
<ui:include src="_#{bean.insertMode eq 'SINGLE' ? 'single' : 'double'}.xhtml" />
または、ファイル名としてinsertMode
を直接使用することもできます。
<ui:include src="_#{fn:toLowerCase(bean.insertMode)}.xhtml" />
どちらの方法でも、#{bean.insertMode}
はビューのビルド時に使用できます。また、ポストバックのビューの復元フェーズでも、最初のレンダリング時とまったく同じ値を使用できます。そうでない場合、ビューが間違ったインクルードで復元され、JSFがデコードできません。正しい入力とコマンドはもうありません。また、ポストバック中にインクルードを変更する場合は、ビューを再構築する(非null
/void
を返す)か、リダイレクトを送信する必要があります。