I'm just learning JSF 2 thanks to this site I had learned a lot in such a short time.
My question is regarding how to implement a common layout to all my JSF 2 pages and have only the content part of the page refresh not the whole page whenever I click a link/menu from a different panel. I am using the Facelets approach it does what I want except that each time I click a link from a panel (e.g. menu items from left panel) the whole page is refreshed. What I am looking for is a way to refresh only the content part of my page. To illustrate this below is my target pagelayout.
Did not post my code because I'm not sure if Facelets can do this . Are there other approach more suited for my requirement other than Facelets?
Netbeans provides a wizard that create the proposed layout with minimal effort using JSF. So, the best way to start is take a look at Facelets Template Wizard and look at the generated source.
If you only want to refresh part of the page, there are only 2 ways to go (for the web in general, not just JSF). You have to use frames or Ajax. JSF 2 supports ajax natively, check out the f:ajax tag to update just 1 component without reloading the entire page.
A straightforward approach would be the following view:
With this bean:
In this example, the actual include templates are
include1.xhtml
,include2.xhtml
andinclude3.xhtml
in/WEB-INF/includes
folder (folder and location is fully free to your choice; the files are just placed in/WEB-INF
in order to prevent direct access by guessing the URL in browser's address bar).This approach works in all MyFaces versions, but requires a minimum of Mojarra 2.3.0. In case you're using a Mojarra version older than 2.3.0, then this all fails when the
<ui:include>
page in turn contains a<h:form>
. Any postback will fail because it is totally missing the view state. You can solve this by upgrading to minimally Mojarra 2.3.0 or with a script found in this answer h:commandButton/h:commandLink does not work on first click, works only on second click, or if you're already using JSF utility library OmniFaces, use its FixViewState script. Or, if you're already using PrimeFaces and exclusively use<p:xxx>
ajax, then it's already transparently taken into account.Also, make sure that you're using minimally Mojarra 2.1.18 as older versions will fail in keeping the view scoped bean alive, causing the wrong include being used during postback. If you can't upgrade, then you'd need to fall back to the below (relatively clumsy) approach of conditionally rendering the view instead of conditionally building the view:
The disadvantage is that the view would become relatively large and that all associated managed beans may be unnecessarily initialized even though when they would not be used as per the rendered condition.
As to positioning of the elements, that's just a matter of applying the right CSS. That's beyond the scope of JSF :) At least,
<h:panelGroup layout="block">
renders a<div>
, so that should be good enough.Last but not least, this SPA (Single Page Application) approach is not SEO friendly. All the pages are not indexable by searchbots nor bookmarkable by endusers, you may need to fiddle around with HTML5 history in client and provide a server side fallback. Moreover, in case of pages with forms, the very same view scoped bean instance would be reused across all pages, resulting in unintuitive scoping behavior when you navigate back to a previously visited page. I'd suggest to go with templating approach instead as outlined in 2nd part of this answer: How to include another XHTML in XHTML using JSF 2.0 Facelets? See also How to navigate in JSF? How to make URL reflect current page (and not previous one).