web-dev-qa-db-ja.com

JSF条件付きインクルード、原因コンポーネントIDはすでにビューで見つかりました

同じビューツリーにあるコンポーネントの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のコンテナーコンポーネントでラップしないでください!

22
Hatem Alimam

重複するコンポーネント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を返す)か、リダイレクトを送信する必要があります。

以下も参照してください。

33
BalusC