このサイトのおかげでJSF 2を学んでいるのは、この短い期間で多くのことを学んだからです。
私の質問は、すべてのJSF 2ページに共通のレイアウトを実装し、別のパネルからリンク/メニューをクリックするたびにページ全体ではなくページのコンテンツ部分のみを更新する方法に関するものです。私はFaceletsアプローチを使用していますが、パネルからリンクをクリックするたびに(左パネルのメニュー項目など)ページ全体が更新されることを除いて、私が望むことをします。私が探しているのは、ページのコンテンツ部分のみを更新する方法です。これを以下に説明するのが、私のターゲットのページレイアウトです。
Faceletsでこれができるかどうかわからないため、コードを投稿しませんでした。 Facelets以外に私の要件により適した他のアプローチはありますか?
簡単なアプローチは次のビューです。
<h:panelGroup id="header" layout="block">
<h1>Header</h1>
</h:panelGroup>
<h:panelGroup id="menu" layout="block">
<h:form>
<f:ajax render=":content">
<ul>
<li><h:commandLink value="include1" action="#{bean.setPage('include1')}" /></li>
<li><h:commandLink value="include2" action="#{bean.setPage('include2')}" /></li>
<li><h:commandLink value="include3" action="#{bean.setPage('include3')}" /></li>
</ul>
</f:ajax>
</h:form>
</h:panelGroup>
<h:panelGroup id="content" layout="block">
<ui:include src="/WEB-INF/includes/#{bean.page}.xhtml" />
</h:panelGroup>
このBeanの場合:
@ManagedBean
@ViewScoped
public class Bean implements Serializable {
private String page;
@PostConstruct
public void init() {
page = "include1"; // Default include.
}
// +getter+setter.
}
この例では、実際のインクルードテンプレートはinclude1.xhtml
、include2.xhtml
およびinclude3.xhtml
in /WEB-INF/includes
フォルダー(フォルダーと場所は自由に選択できます。ファイルは/WEB-INF
ブラウザのアドレスバーのURLを推測して直接アクセスを防止するために 。
このアプローチはすべてのMyFacesバージョンで機能しますが、少なくともMojarra 2.3.0が必要です。 2.3.0より古いバージョンのMojarraを使用している場合、<ui:include>
ページには<h:form>
。ビューステートが完全に欠落しているため、ポストバックは失敗します。これを最小限に抑えるには、Mojarra 2.3.0にアップグレードするか、この回答に記載されているスクリプトを使用します h:commandButton/h:commandLinkは最初のクリックでは機能せず、2回目のクリックでのみ機能します 、またはすでにJSFユーティリティライブラリ OmniFaces を使用している場合は、その FixViewStateを使用しますスクリプト 。または、すでにPrimeFacesを使用しており、<p:xxx>
ajax、それはすでに透過的に考慮されています。
また、古いバージョンではビュースコープBeanを有効に保つことができず、ポストバック中に誤ったincludeが使用されるため、Mojarra 2.1.18を最低限使用していることを確認してください。アップグレードできない場合は、条件付きでビューを構築するのではなく、ビューを条件付きでレンダリングする以下の(比較的不器用な)アプローチにフォールバックする必要があります。
...
<h:panelGroup id="content" layout="block">
<ui:fragment rendered="#{bean.page eq 'include1'}">
<ui:include src="include1.xhtml" />
</ui:fragment>
<ui:fragment rendered="#{bean.page eq 'include2'}">
<ui:include src="include2.xhtml" />
</ui:fragment>
<ui:fragment rendered="#{bean.page eq 'include3'}">
<ui:include src="include3.xhtml" />
</ui:fragment>
</h:panelGroup>
欠点は、ビューが比較的大きくなり、関連付けられたすべての管理対象Beanがレンダリング条件に従って使用されない場合でも、不必要に初期化される可能性があることです。
要素の配置に関しては、正しいCSSを適用するだけです。それはJSFの範囲外です:)少なくとも、<h:panelGroup layout="block">
は<div>
、それで十分なはずです。
最後になりましたが、このSPA(シングルページアプリケーション)アプローチはSEOに適していません。すべてのページは、サーチボットによる索引付けもエンドユーザーによるブックマーク付けもできません。クライアントでHTML5履歴をいじり、サーバー側のフォールバックを提供する必要がある場合があります。さらに、フォームのあるページの場合、まったく同じビュースコープBeanインスタンスがすべてのページで再利用されるため、以前にアクセスしたページに戻ったときに直感的ではないスコーピング動作が発生します。この回答の第2部で概説されているように、代わりにテンプレートアプローチを使用することをお勧めします: JSF 2.0 Faceletsを使用してXHTMLに別のXHTMLを含める方法? また JSFでナビゲートする方法は? URLに現在のページを反映させる方法(前のページではなく) 。
ページの一部のみを更新したい場合は、2つの方法しかありません(JSFだけでなく、一般的なWebの場合)。フレームまたはAjaxを使用する必要があります。 JSF 2はajaxをネイティブでサポートしています。ページ全体をリロードせずに1つのコンポーネントのみを更新するには、f:ajaxタグをチェックしてください。