Mojarra-2.1.3 as per Glassfish3.1.1 (distributed with Netbeans7.1)
I have a @SessionScoped backing bean Tracker with a listener void reset().
The following works fine in the f:metadata of all XHTML pages that use a template.xhtml, for example /block/view.xhtml, which also takes a query parameter id:
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{blockManager.id}"/>
<f:event type="preRenderView" listener="#{tracker.reset}"/>
</f:metadata>
</f:view>
<ui:composition template="/template.xhtml">
As expected, whenever I load (GET) or reload a page, and no matter what the id query parameter, the #{tracker.reset} listener is invoked (as revealed by debug logging).
However, it is tedious to have to include that f:event in every XHTML page (of which I have hundreds), I tried first instead to have it in the f:metadata of my template.xhtml. But when I did something strange happened. It only called #{tracker.reset} once, the first time /block/view.xhtml was loaded (no matter what the id query parameter was), and thereafter it was not called again until I loaded another page with a different viewId, such as /actor/view.xhtml, or /block/list.xhtml, or /index.html.
I examined the viewId using #{facesContext.viewRoot.viewId} in the template.xhtml. It is clear from the point of view of the viewId that the query parameter id plays no role in distinguishing between different block/view.xhtml?id=[id] pages called with different id query parameters, the viewId is always just '/block/view.xhtml'.
During the writing of this stackoverflow posting I discovered the solution to my problem: just place the f:event outside the f:metadata of the template.xhtml (I was using the f:metadata in the template.xhtml for grouping of f:events). This works in template.xhtml:
<f:metadata>
..
</f:metadata>
<f:event type="preRenderView" listener="#{tracker.reset}"/>
<h:head>
But I still have the following question:
Q: Why does it make a difference whether or not I place an f:event inside the f:metadata in a template ?
The reason I ask is that there are lots of examples here on Stackoverflow both of use of an f:metadata in a template.xhtml, and of an f:event inside an f:metadata in a template.
BalusC states at When to use f:viewAction / preRenderView versus PostConstruct?:
The preRenderView event is invoked on every HTTP request.
This only seems to be true (to work as expected) if I have the preRenderView f:event in the f:metadata of the final XHTML page, or outside the f:metadata of a template, but not inside the f:metadata of a template.
There seems to be some debate about whether one should have f:event in the f:metadata of a template, or use f:metadata in a template at all.
JSF2 Complete Reference (Burns and Schalk) p.540 states:
The f:metadata tag encapsulates the set of elements used to specify the metadata for a Facelets view, and therefore must be the child of the f:view tag and may not appear in a template. As of JSF2.0, the only purpose of this tag is to encapsulate f:viewParam tags.
But there are lots of examples on Stackoverflow of f:metadata being used inside templates, and there are lots of examples of f:event being used inside f:metadata. It is also discussed here:
Does it matter whether place f:event inside f:metadata or not?
Where BalusC helpfully explained:
.. the <f:event> is not strictly required to be placed inside <f:metadata>. It can be attached to any component. .. It's indeed for pure self-documentary purposes placed inside the <f:metadata> whenever you have a bunch of <f:viewParam>s and would like to hook a <f:event> to invoke an action after all those view parameters have been set. ..
But my experience above indicates that placing and f:event inside an f:metadata of a template gives slightly different (strange) behaviour. Why ?