JSF/CDI: General way to update page content - jsf

what is the general way when requesting new pages with given parameters, i.e. calling CDI bean operations and bind the outcome to the page components?
I am using this 'pattern', but is this the right way?
<ui:define name="content">
<h:form id="dataForm">
#{userForm.init(param.id, param.mode)}
<!-- User edit Dialog -->
<p:panel>
...
</:panel>
</h:form>
</ui:define>
The problem is that when using the 'rendered' attribute, this depends on the bean (non-blocking) process outcome but the page might be rendered faster. Thus, I should be able to call an update process on the page UI components after processing.

If you are using JSF 2.2 the way to go is:
<f:metadata>
<f:viewAction action="#{backingBean.action}"/>
</f:metadata>
If you are < JSF2.2 but you happen to be using Seam you could use something like this as a pre-render view event, it does not have to be in a template, you can drop it in your ui:composition
XHTML
xmlns:s="http://jboss.org/seam/faces"
<f:metadata>
<s:viewAction action="#{backingBean.action}" />
</f:metadata>
here is something to read Seam3, if not you can always use the classic way:
<f:metadata>
<f:viewParam name="id" value="#{backingBean.entryId}"/>
<f:event type="preRenderView" listener="#{backingBean.loadEntry}"/>
</f:metadata>

Related

Multiple <f:viewAction> in <f:metadata>

I am developing a CMS using JSF 2.3. I need to pass a GET parameter to every page indicating the site that the user is managing. To do this I am using <f:viewParam> in all pages, but I have the following doubts:
Is it OK to use multiple <f:viewAction> for multiple managed beans like the following example?
<f:metadata>
<f:viewParam name="form" value="#{editFormWebBean.formIdParam}"/>
<f:viewParam name="site" value="#{headerWebBean.siteIdParam}"/>
<f:viewAction action="#{editFormWebBean.init}" />
<f:viewAction action="#{headerWebBean.init}" />
</f:metadata>
This works, but I am not sure if it is OK.
Is there a way to avoid replicating in every page the <f:viewParam> for the site parameter? I tried with includeViewParams, but doesn't worked if I don't include the <f:viewParam> in the source and destination page (from page1.xhtml to page2.xhtml)
3) Can I define multiple <f:metadata> tags? For example if I am using templates and multiple ManagedBeans pare page (one for the header, one for the menu and so on).
Thank you and sorry about my english.
it's okay to have as many <f:viewParam> and <f:viewAction> as long as they work well together, but please make sure these are meant to initialize the view "JSF page" not the backing beans, use #PostConstruct on the baking beans to initialize them, also but in your mind that <f:viewAction> is only executed on GET request by default any subsequent POST (postback) requests don't invoke the action unless it has onPostBack="true" attribute.
more on these tags can be found in this great answer
[What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?][1]
put it in a template using the templating feature of JSF like this:
template.xhtml
<f:metadata>
<f:viewParam name="site" value="#{headerWebBean.siteIdParam}"/>
<ui:insert name="metadata"/>
</f:metadata>
page.xhtml
<ui:composition template="template.xhtml">
<ui:define name="metadata">
<!-- whatever metadata you want to add-->
</ui:define>
</ui:comosition>
no it's one metadata tag per page, use it like the example above.
[1]: https://stackoverflow.com/a/6377957/4649524

How share some f:event of f:metadata between selected XHTML with managed bean interface as parameter

Noting that from JSF view metadata demystified:
Since this tag is about current view metadata it doesn't participate
in XHTML templates (the page author must ensure that the
element does not appear on a template or included page; it can be in a
template client) and it is direct child of <f:view>.
I have multiple <f:viewParam> and <f:event> that repeat in many XHTML pages, which are in turn clients of a template.xhtml. Each f:event depends on a given managed bean, where the managed bean is different for each XHTML page (but respects a common interface, i.e., the same operations for the listeners exist for every relevant managed bean):
<f:view>
<f:metadata>
<!-- I want to share this across many XHTML parametrised by the bean -->
<f:viewParam name="id" value="#{particularBean.id}"/>
<f:event type="preRenderView" listener="#{particularBean.opCommon1}"/>
<f:event type="preRenderView" listener="#{particularBean.opCommon2}"/>
<!-- END SHARED PORTION -->
<f:event type="preRenderView" listener="#{particularBean.onlyForMe}"/>
</f:metadata>
</f:view>
<ui:composition template="/template.xhtml">
Q: How can I encapsulate the shared <f:viewParam> and <f:event> portion so that it can be "included" and treated as a common policy fragment, with particular managed beans (meeting the common interface) passed in for each XHTML page ?
I found the answer in one of my own older projects (as I posted I recalled vaguely I had investigated this already at some stage years ago). This works:
In /include/shared.xhtml:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
>
<f:viewParam name="id" value="#{particularBean.id}"/>
<f:event type="preRenderView" listener="#{compatibleBean.opCommon1}"/>
<f:event type="preRenderView" listener="#{compatibleBean.opCommon2}"/>
</ui:composition>
And in any client:
<f:view>
<f:metadata>
<ui:include src="/included/shared.xhtml">
<ui:param name="compatibleBean" value="#{particularBean}"/>
</ui:include>
<f:event type="preRenderView" listener="#{particularBean.onlyForMe}"/>
</f:metadata>
</f:view>

JSF: duplicate component id exception when including the same facelets tag twice

I have a facelets tag like this:
<ui:composition>
<h:outputText value="#{label}"/>
<h:inputText id="input" value="#{value}"/>
<h:message for="input"/>
</ui:composition>
Now if I inlcude this facelets tag twice on the same page, I get an exception complaining about duplicate compoment ids. One solution proposed here https://stackoverflow.com/a/21572756/1785730 was to supply a prefix for the id. However, I find it cumbersome having to come up with an id prefix every time I use this facelets tag. By the way, I don't need the id of the h:inputText outside of the tag.
So I'm thinking of two ways how I can fix this:
Is there a way to link the h:message to the h:inputText without having to specify ids?
If not, I could wrap the tag with a NamingContainer. Which element would be appropriate for that? I can't use h:form here, because that tag already goes into a form.
Your page should be like this
<f:view contracts="default" transient="false">
<ui:composition template="/template.xhtml">
<ui:define name="content">
<h:form>
inputs
</h:form>
</ui:define>
</ui:composition>
</f:view>
inside ui composition you should have ui define and in it form and inputs.

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?
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.

How to call the same method after every include of a .xhtml page in JSF?

I have the following part of a .xhtml page:
<ui:composition template="./templates/template.xhtml">
<ui:define name="mainContent">
<ui:include src="include/includeAbleEditor.xhtml">
<ui:param name="includeParam" value="MyClass" />
</ui:include>
<ui:include src="include/includeAbleEditor.xhtml">
<ui:param name="includeParam" value="YourClass" />
</ui:include>
</ui:define>
In the "includeAbleEditor.xhtml" I want to call a method after it was included (In this case this should happend two times).
Now I tried to solve it like this: (metadata tag is part of the includeAbleEditor.xhtml)
<f:metadata>
<f:event type="preRenderView" listener="#{editor.onload}" />
<f:attribute name="textFieldId" value="#{includeParam}" />
</f:metadata>
The Problem:
The method is being called only once. But it should be called two times. Once with the parameter "MyClass" and once with "YourClass".
Do you have any suggestions?
Thanks a lot!
There can be only one <f:metadata> in the entire view and it must be in the top level view. Unlike e.g. <f:view>, they don't "extend" each other and all others will be ignored.
You actually don't need it here. It's only necessary whenever you need to attach <f:viewParam> and/or <f:viewAction> to the specific view. The <f:event> doesn't require a <f:metadata>. It will just be hooked to the parent UIComponent. It was during JSF 2.0/2.1 ages (when <f:viewAction> didn't exist) being abused to have a hook to invoke a listener after <f:viewParam> values are being set. It's just for self-documentary purposes being placed in the same <f:metadata> as where all <f:viewParam>s are.
So, just get rid of it.
<f:event type="preRenderView" listener="#{editor.onload(includeParam)}" />
That said, postAddToView is likely a better event to hook this all on. And to avoid "Duplicate component ID" errors over all place later on, consider wrapping it in <f:subview> or making it a composite.
See also:
When using <ui:composition> templating, where should I declare the <f:metadata>?
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Avoiding duplicate ids when reusing facelets compositions in the same naming container

Resources