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

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>

Related

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

JSF/CDI: General way to update page content

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>

Validation of ViewParam and a4j:commandButton

I think i came across a bug of #ViewScoped with a4j:commandButton.
I have a very complex form where all actions use a4j, except those that need to upload data.
And depending on the order of the commands the validation of the viewParam breaks.
Here is the working code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j" >
<f:metadata>
<f:viewParam id="viewParam" name="viewParam" value="#{bean.viewParam}" required="true" />
</f:metadata>
<h:head>
<title>Test View Param</title>
</h:head>
<h:body>
<h:message for="viewParam" />
<hr/>
<h:form>
#{bean.viewParam}<br/>
<h:commandButton value="cmdButton" />
<a4j:commandButton value="a4jBtn" execute="#this" render="#form" />
</h:form>
</h:body>
</html>
just click on the a4jBtn and then on the cmdButton to see the problem.
you will see that the parameter is still there! but that the validation fails.
<t:saveState> does not help,
<rich:message> is also not better, but
<h:commandButton value="ajaxBtn" ><f:ajax execute="#this" render="#form" /></h:commandButton>
instead of
<a4j:commandButton value="a4jBtn" execute="#this" render="#form" />
does work correctly!
Using myFaces 2.0.15 and richFaces 4.2.3.Final on Tomcat 6.0.18 and jboss-el 2.0.0.GA.
i could workaround my problem by using f:ajax instead of a4j:commandButton, but maybe you have a better idea, or you could just explain to me what is going wrong?
You basically need to retain the view parameters on synchronous postbacks. As you're using OmniFaces, you could use <o:form> for that.
<o:form includeViewParams="true">
Or as you're already using a view scoped bean, trigger the validation only on non-postbacks.
<f:viewParam ... required="#{not facesContext.postback}" />
Or, as you're using OmniFaces, you could use <o:viewParam> instead which skips the validation/conversion/update on postbacks.
<o:viewParam ... />

Getting page parameters for a requestscoped bean in a form

I have the following page:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>Fire - Registration</title>
</h:head>
<h:body>
<f:view>
<f:event type="preRenderView" listener="#{confirmPasswordResetBean.bindSessionKey()}"/>
</f:view>
<p:growl id="growl" showDetail="true" life="5000" />
<h:form>
<p:panel header="Select your new password">
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel for="newPassword" value="Type your new password"/>
<p:password id="newPassword"
value="#{confirmPasswordResetBean.firstPassword}"
feedback="true"/>
<p:outputLabel for="retypedPassword" value="Retype your password"/>
<p:password id="retypedPassword"
value="#{confirmPasswordResetBean.secondPassword}"/>
</h:panelGrid>
<p:commandButton id="confirmButton"
value="reset"
action="#{confirmPasswordResetBean.doResetPassword()}"
update=":growl"/>
</p:panel>
</h:form>
</h:body>
The backing bean used above is RequestScoped, and the page itself takes a single parameter (sessionKey)...what I want to do is to:
1. Bind sessionKey to a variable in the backing bean. This is straightforward enough.
2. Use the bound value of sessionKey when executing dedicated logic in the same bean, when the client presses the commandButton.
The problem is that pressing the button starts a new request, which invalidates both the current bean (with the bound value), as well as the external page context...I thus lose all means to get a hold of sessionKey from either the bean or the page parameters...how can I resolve this? I am relatively new to both web programming and JSF, so pardon me if this has an obvious answer.
Either put the bean in the view scope, so that it lives long as you're interacting with the same view, or pass the request parameter by <f:param> to the subsequent requests.
<p:commandButton ...>
<f:param name="sessionKey" value="#{param.sessionKey}" />
</p:commandButton>
By the way, you'd rather have used <f:viewParam> to bind the request parameter to the bean directly.
<f:metadata>
<f:viewParam name="sessionKey" value="#{bean.sessionKey}" />
</f:metadata>
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?

facelets: passing bean name with ui:param to action attribute

Due to some custom components which expect a bean name (NOT the bean instance) in their attributes I need to pass the actual bean name between pages. As the bean itself is also used by non-custom components, I would like to avoid using additional ui:param (like described here Passing action in <rich:modalPanel>) since it will essentially specify the same bean.
Is it possible to specify component's action using bean name provided with ui:param?
Basically I am trying to achieve the following:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="/template.xhtml">
<ui:param name="beanName" value="sessionBean"/>
...
</ui:composition>
and template.xhtml is
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
template="/someothertemplate.xhtml">
</ui:define name="somename">
<h:form>
<a4j:commandButton value="test" action="#{beanName.delete}"/>
</h:form>
</ui:define>
</ui:composition>
Although delete method is properly defined (verified with action="#{sessionBean.delete}") the above code gives me
javax.faces.FacesException: #{beanName.delete}: javax.el.MethodNotFoundException: /template.xhtml #201,89 action="#{beanName.delete}": Method not found: sessionBean.delete()
You should be able to reference the bean via its scope:
<a4j:commandButton value="test"
action="#{sessionScope[beanName].delete}"/>
<a4j:commandButton value="test" action="#{bean[action]}" />
The params to pass
<ui:param name="bean" value="#{sessionBean}" />
<ui:param name="action" value="delete" />
you can use #{bean['delete']} if your action name is fixed.

Resources