条件付きでFaceletsコードを少し出力したいと思います。
そのため、JSTLタグは正常に機能するようです。
<c:if test="${lpc.verbose}">
...
</c:if>
ただし、これがベストプラクティスであるかどうかはわかりませんか?私の目標を達成する別の方法はありますか?
JSTL <c:xxx>
タグはすべて taghandlers であり、これらはview build timeの間に実行され、JSF <h:xxx>
タグはすべて Iコンポーネント であり、レンダリング時間の表示中に実行されます。
JSF独自の<f:xxx>
および<ui:xxx>
タグからは、 UIComponent
からnotを拡張するものだけがタグハンドラーでもあることに注意してください。 <f:validator>
、<ui:include>
、<ui:define>
など。UIComponent
から拡張されるものもJSF UIコンポーネントです。 <f:param>
、<ui:fragment>
、<ui:repeat>
など。JSFUIコンポーネントからは、id
およびbinding
属性のみがビューのビルド時に評価されます。したがって、JSTLライフサイクルに関する以下の回答は、JSFコンポーネントのid
およびbinding
属性にも適用されます。
ビューのビルド時間は、XHTML/JSPファイルが解析され、JSFコンポーネントツリーに変換され、UIViewRoot
のFacesContext
として保存される瞬間です。ビューのレンダリング時間は、UIViewRoot#encodeAll()
で始まるJSFコンポーネントツリーがHTMLを生成しようとする瞬間です。したがって、JSF UIコンポーネントとJSTLタグは、コーディングから予想されるように同期して実行されません。 JSTLは最初に上から下に実行され、JSFコンポーネントツリーを生成し、次にJSFが上から下に再び実行され、HTML出力を生成します。
<c:forEach>
vs <ui:repeat>
たとえば、次のFaceletsマークアップは、<c:forEach>
を使用して3つのアイテムを反復処理します。
<c:forEach items="#{bean.items}" var="item">
<h:outputText id="item_#{item.id}" value="#{item.value}" />
</c:forEach>
...ビューのビルド時に、JSFコンポーネントツリーに3つの別個の<h:outputText>
コンポーネントを作成します。おおよそ次のように表されます。
<h:outputText id="item_1" value="#{bean.items[0].value}" />
<h:outputText id="item_2" value="#{bean.items[1].value}" />
<h:outputText id="item_3" value="#{bean.items[2].value}" />
...次に、ビューのレンダリング時にHTML出力を個別に生成します。
<span id="item_1">value1</span>
<span id="item_2">value2</span>
<span id="item_3">value3</span>
コンポーネントIDの一意性を手動で確認する必要があり、ビューのビルド時にそれらも評価されることに注意してください。
このFaceletsマークアップは、JSF UIコンポーネントである<ui:repeat>
を使用して3つのアイテムを反復処理しますが、
<ui:repeat id="items" value="#{bean.items}" var="item">
<h:outputText id="item" value="#{item.value}" />
</ui:repeat>
...すでにJSFコンポーネントツリーにそのまま残っているため、ビューのレンダリング中に非常に同じ<h:outputText>
コンポーネントがreusedになります現在の反復ラウンドに基づいてHTML出力を生成します。
<span id="items:0:item">value1</span>
<span id="items:1:item">value2</span>
<span id="items:2:item">value3</span>
NamingContainer
コンポーネントである<ui:repeat>
は、繰り返しインデックスに基づいてクライアントIDの一意性を既に確保していることに注意してください。子コンポーネントのid
属性でELを使用することもできません。これは、ビューのビルド時にも評価されるため、#{item}
はビューのレンダリング時にのみ使用できます。 h:dataTable
および同様のコンポーネントについても同様です。
<c:if>
/<c:choose>
vs rendered
別の例として、このFaceletsマークアップは<c:if>
を使用して条件付きで異なるタグを追加します(これには<c:choose><c:when><c:otherwise>
も使用できます)。
<c:if test="#{field.type eq 'TEXT'}">
<h:inputText ... />
</c:if>
<c:if test="#{field.type eq 'PASSWORD'}">
<h:inputSecret ... />
</c:if>
<c:if test="#{field.type eq 'SELECTONE'}">
<h:selectOneMenu ... />
</c:if>
...type = TEXT
の場合、<h:inputText>
コンポーネントのみをJSFコンポーネントツリーに追加します。
<h:inputText ... />
このFaceletsマークアップ中:
<h:inputText ... rendered="#{field.type eq 'TEXT'}" />
<h:inputSecret ... rendered="#{field.type eq 'PASSWORD'}" />
<h:selectOneMenu ... rendered="#{field.type eq 'SELECTONE'}" />
... JSFコンポーネントツリーでは、条件に関係なく、上記のとおりになります。したがって、これが多くあり、それらが実際に「静的」モデルに基づいている場合(つまり、field
は少なくともビュースコープの間は変更されません)、「肥大化した」コンポーネントツリーになることがあります。また、2.2.7より前のMojarraバージョンで追加プロパティを持つサブクラスを扱う場合、EL trouble に遭遇する可能性があります。
<c:set>
vs <ui:param>
それらは互換性がありません。 <c:set>
は、ELスコープ内の変数を設定します。これは、ビューのビルド時はタグの位置の後からのみアクセスできますが、ビューのレンダリング時はビューのどこからでもアクセスできます。 <ui:param>
は、<ui:include>
、<ui:decorate template>
、または<ui:composition template>
を介して含まれるFaceletテンプレートにEL変数を渡します。古いJSFバージョンには、問題のFaceletテンプレートの外部で<ui:param>
変数も使用できるというバグがありました。これに依存しないでください。
scope
属性のない<c:set>
は、エイリアスのように動作します。 EL式の結果はどのスコープにもキャッシュされません。したがって、たとえばJSFコンポーネントの反復処理などの内部で完全に使用できます。したがって、例えば以下は正常に動作します:
<ui:repeat value="#{bean.products}" var="product">
<c:set var="price" value="#{product.price}" />
<h:outputText value="#{price}" />
</ui:repeat>
それは例えばに適していませんループで合計を計算します。その代わりに EL 3.0ストリーム を使用します。
<ui:repeat value="#{bean.products}" var="product">
...
</ui:repeat>
<p>Total price: #{bean.products.stream().map(product->product.price).sum()}</p>
のみ、scope
属性に許容値request
、view
、session
、またはapplication
のいずれかを設定すると、ビューのビルド時にすぐに評価され、指定されたスコープに格納されます。
<c:set var="dev" value="#{facesContext.application.projectStage eq 'Development'}" scope="application" />
これは一度だけ評価され、アプリケーション全体で#{dev}
として利用できます。
JSTLの使用は、<h:dataTable>
、<ui:repeat>
などのJSF反復コンポーネント内で使用される場合、またはJSTLタグ属性がpreRenderView
などのJSFイベントの結果に依存する場合、またはビューのビルド時に使用できないモデル。したがって、JSTLコンポーネントのツリー構築のフローを制御するためだけにJSTLタグを使用してください。 JSF UIコンポーネントを使用して、HTML出力生成のフローを制御します。反復するJSFコンポーネントのvar
をJSTLタグ属性にバインドしないでください。 JSTLタグ属性のJSFイベントに依存しないでください。
binding
を介してコンポーネントをバッキングBeanにバインドするか、findComponent()
を使用してコンポーネントを取得し、new SomeComponent()
を使用してバッキングBeanのJavaコードを使用して子を作成/操作する必要があると思う場合は、すぐに停止し、代わりにJSTLの使用を検討してください。 JSTLもXMLベースであるため、JSFコンポーネントを動的に作成するために必要なコードは非常に読みやすく、保守しやすくなります。
知っておくべき重要なことは、2.1.18よりも古いバージョンのMojarraには、JSTLタグ属性でビュースコープBeanを参照するときに部分的な状態の保存にバグがあったことです。ビュースコープBean全体は、ビューツリーから取得するのではなく、newly再作成されます(JSTLの時点で完全なビューツリーがまだ利用できないためです)実行)。 JSTLタグ属性によってビュースコープBeanに状態を予期または格納している場合、期待値を返さないか、ビューの後に復元される実際のビュースコープBeanで「失われます」ツリーが構築されます。 Mojarra 2.1.18以降にアップグレードできない場合、次のようにweb.xml
で部分的な状態の保存をオフにすることで回避できます。
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
@ViewScoped
はタグハンドラで失敗しますJSTLタグが役立つ実際の例(ビューの構築中に実際に適切に使用される場合)を確認するには、次の質問/回答を参照してください。
具体的な機能要件について、条件付きでJSFコンポーネントをrenderしたい場合は、代わりにJSF HTMLコンポーネントのrendered
属性を使用します特に#{lpc}
が、<h:dataTable>
や<ui:repeat>
などのJSF反復コンポーネントの現在反復されている項目を表す場合。
<h:someComponent rendered="#{lpc.verbose}">
...
</h:someComponent>
または、条件付きでJSFコンポーネントをbuild(作成/追加)する場合は、JSTLを使用し続けます。 Javaでnew SomeComponent()
を冗長に実行するよりもはるかに優れています。
<c:if test="#{lpc.verbose}">
<h:someComponent>
...
</h:someComponent>
</c:if>
つかいます
<h:panelGroup rendered="#{lpc.verbose}">
...
</h:panelGroup>
個別の回答で申し訳ありませんが、上記の回答をコメントできませんでした。
スイッチのような出力の場合、 primefaces-extensions からスイッチを使用できます。