Search code examples
jsffaceletsjsf-2.2

If I can't use f:viewAction within a JSF template, where can I put generic post-URL processing code?


I have a generic JSF page and abstract class that is implemented by many other pages and used to do its main processing in a @PostConstruct method. Now that I'm using URL parameters for some of the pages, I want to move all of the pages' processing into a viewAction action method instead so that it can use the URL parameters in their processing.

Of course, I can't use f:metadata/f:viewAction in my template because that's not allowed by JSF:

When using <ui:composition> templating, where should I declare the <f:metadata>?

Is there a way to handle post-viewAction processing by all of my pages in a generic manner? Right now I have it working with an f:event tag:

Template page:

<ui:insert name="metadata"/>

<h:head>
    <f:event type="preRenderComponent" listener="#{controller.postProcessParams}" />
</h:head>

Client page:

<ui:define name="metadata">
    <f:metadata>
        <f:param name="id" value="#{manageProjects.id}"/>
        <f:viewAction action="#{manageProjects.processParams}"/>
    </f:metadata>
</ui:define>

<ui:param name="controller" value="#{manageProjects}"/>   

Is this proper though?


Solution

  • Better use preRenderView instead of preRenderComponent, particularly if the method could potentially throw an exception and/or perform a navigation/redirect, otherwise you could potentially face an incomplete response and/or kind of "Response already committed" exception when it has taken place.

    The preRenderView is basically like attaching preRenderComponent on <f:view>/UIViewRoot. I.e. before the entire view get rendered and thus guaranteed to run before any bit gets written to the HTTP response body. You'd rather not perform business logic while JSF is busy generating HTML output.

    For the remainder, the templating approach is OK.