How to retrieve value of a ui:param in the backing bean - jsf-2

I'm passing a parameter p1 to another page page.xhtml:
<ui:include src="page.xhtml">
<ui:param name="p1" value="#{someObject}"/>
</ui:include>
Is this possible to evaluate #{p1} inside #PostConstruct method of the backing bean of page.xhtml? Using the following piece of code, #{p1} cannot resolve:
FacesContext currentInstance = FacesContext.getCurrentInstance();
currentInstance.getApplication().evaluateExpressionGet(currentInstance, "#{p1}", String.class);
Why do I need this?
I'm using an xhtml file (say component.xhtml) as a custom UI component. This file has a backing bean from which I should get component data. Since I'm including this xhtml file twice or more in my main JSF page, I want to pass different objects to each of component.xhtml so that my component work with my custom data each time included.

In Mojarra, you can get it as an attribute of the FaceletContext. You can get it in the #PostConstruct of a managed bean which is guaranteed to be referenced/constructed for the first time in the included page (and thus not in the parent page before the <ui:param> is declared in the component tree).
FaceletContext faceletContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
Object p1 = faceletContext.getAttribute("p1");
In MyFaces, the whole FaceletContext isn't available in managed beans as it's discarded by end of view build time and this construct would then not work. To be JSF implementation independent, you might want to consider to set it via <c:set scope="request"> instead. It's then available as a request attribute.
As to the concrete functional requirement, consider creating a comoposite component with a backing component. For some examples, see our composite component wiki page and this blog about using multiple input components in a composite component. See also When to use <ui:include>, tag files, composite components and/or custom components?

The param is not available in the #PostConstruct method; you can use the preRenderComponent event to initialize the parameters inside your backing bean; just put it after the ui:composition of the included page, it will be executed before the rendering of the included page itself.
Following the OP example of a passing a p1 parameter to a page.xhtml template
the main page:
<ui:include src="page.xhtml">
<ui:param name="p1" value="#{someObject}"/>
</ui:include>
page.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
...>
<ui:composition>
<f:event listener="#{backingBean.init(p1)}" type="preRenderComponent"/>
...
</ui:composition>
</html>
BackingBean.java:
#ViewScoped
public class BackingBean{
private Object p1;
public void init(Object value){
this.p1=p1;
}
...
}
the event is fired before the render of the ui:composition tag, that is before the render of page.xhtml

This works for me:
<ui:include src="page.xhtml">
<ui:param name="p1" value="#{someObject}"/>
</ui:include>
page.xhtml:
<c:set var="data" value="#{p1}" scope="request"/>
Your bean:
#ViewScoped
public class ManagedBean{
private Object someObject;
public Object getSomeObject(){
if(someObject== null){
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
someObject= request.getAttribute("data");
}
return someObject;
}
public void setSomeObject(Object someObject){
this.someObject = someObject;
}}

Related

Passing and using parameters between JSF includes

I've been trying to understand JSF templating and include attributes and passing parameters between components. In Mastering JavaServer Faces 2.2 by Anghel Leonard, I came across the following example of passing parameters, which I don't fully understand.
Given this bean:
#Named
#ViewScoped
public class TemplatesBean implements Serializable {
private String msgTopDefault="";
private String msgBottomDefault="";
private String msgCenterDefault="No center content ... press the below button!";
public void centerAction(){
this.msgCenterDefault="This is default content";
}
// Getters and setters
}
Parameters are passed to contentDefault.xhtml with:
<ui:insert name="content">
<ui:include src="/template/default/contentDefault.xhtml">
<ui:param name="templatesBeanName" value="#{templatesBean}"/>
<ui:param name="contentPropertyName" value="msgCenterDefault"/>
</ui:include>
</ui:insert>
Then, within contentDefault.xhtml the parameters are used as follows:
<ui:composition>
<h:outputText value="#{templatesBeanName[contentPropertyName]}"/>
<h:form>
<h:commandButton value="Center Button" action="#{templatesBeanName['centerAction']()}"/>
</h:form>
</ui:composition>
I've never used the square-bracket syntax before, but if a reference to templatesBean is being passed in, why not just use that to access the properties or invoke action methods? For example, the following code works for me too and seems simpler:
<h:form>
<h:commandButton value="Center Button" action="#{templatesBeanName.centerAction()}"/>
</h:form>
Recognising that the example in the book may be a contrived example to illustrate a point, are there use cases where the other syntax is appropriate?
I do not know or own the book, so I cannot investigate that way what they want to illustrate, but I can sort of deduce that by looking at the full example you posted, not just the part about the centerAction.
If you look at
<ui:insert name="content">
<ui:include src="/template/default/contentDefault.xhtml">
<ui:param name="templatesBeanName" value="#{templatesBean}"/>
<ui:param name="contentPropertyName" value="msgCenterDefault"/>
</ui:include>
</ui:insert>
you'll see that 2 params are passesd on, templatesBeanName and contentPropertyName
In
<ui:composition>
<h:outputText value="#{templatesBeanName[contentPropertyName]}"/>
<h:form>
<h:commandButton value="Center Button" action="#{templatesBeanName['centerAction']()}"/>
</h:form>
</ui:composition>
from which you just pointed to the line with action="#{templatesBeanName['centerAction']()}", a dynamic bean with a static value in suqare brackets made into a method by adding () as a postfix, you'll see another line of code above it
<h:outputText value="#{templatesBeanName[contentPropertyName]}"/>
What effectively is done here is to have a dynamic bean AND a dynamic property name being used.
So my conclusion is that with this example what they are trying to illustrate is that you are able to pass on a dynamic bean, and on that bean use either both static or dynamic methods and properties(static properties and dynamic methods not being in the example)

Fail to set timezone in <f:convertDateTime> [duplicate]

Is there a way to execute a JSF managed bean action when a page is loaded?
If that's relevant, I'm currently using JSF 1.2.
JSF 1.0 / 1.1
Just put the desired logic in the constructor of the request scoped bean associated with the JSF page.
public Bean() {
// Do your stuff here.
}
JSF 1.2 / 2.x
Use #PostConstruct annotated method on a request or view scoped bean. It will be executed after construction and initialization/setting of all managed properties and injected dependencies.
#PostConstruct
public void init() {
// Do your stuff here.
}
This is strongly recommended over constructor in case you're using a bean management framework which uses proxies, such as CDI, because the constructor may not be called at the times you'd expect it.
JSF 2.0 / 2.1
Alternatively, use <f:event type="preRenderView"> in case you intend to initialize based on <f:viewParam> too, or when the bean is put in a broader scope than the view scope (which in turn indicates a design problem, but that aside). Otherwise, a #PostConstruct is perfectly fine too.
<f:metadata>
<f:viewParam name="foo" value="#{bean.foo}" />
<f:event type="preRenderView" listener="#{bean.onload}" />
</f:metadata>
public void onload() {
// Do your stuff here.
}
JSF 2.2+
Alternatively, use <f:viewAction> in case you intend to initialize based on <f:viewParam> too, or when the bean is put in a broader scope than the view scope (which in turn indicates a design problem, but that aside). Otherwise, a #PostConstruct is perfectly fine too.
<f:metadata>
<f:viewParam name="foo" value="#{bean.foo}" />
<f:viewAction action="#{bean.onload}" />
</f:metadata>
public void onload() {
// Do your stuff here.
}
Note that this can return a String navigation case if necessary. It will be interpreted as a redirect (so you do not need a ?faces-redirect=true here).
public String onload() {
// Do your stuff here.
// ...
return "some.xhtml";
}
See also:
How do I process GET query string URL parameters in backing bean on page load?
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
How to invoke a JSF managed bean on a HTML DOM event using native JavaScript? - in case you're actually interested in executing a bean action method during HTML DOM load event, not during page load.
Another easy way is to use fire the method before the view is rendered. This is better than postConstruct because for sessionScope, postConstruct will fire only once every session. This will fire every time the page is loaded. This is ofcourse only for JSF 2.0 and not for JSF 1.2.
This is how to do it -
<html xmlns:f="http://java.sun.com/jsf/core">
<f:metadata>
<f:event type="preRenderView" listener="#{myController.onPageLoad}"/>
</f:metadata>
</html>
And in the myController.java
public void onPageLoad(){
// Do something
}
EDIT - Though this is not a solution for the question on this page, I add this just for people using higher versions of JSF.
JSF 2.2 has a new feature which performs this task using viewAction.
<f:metadata>
<f:viewAction action="#{myController.onPageLoad}" />
</f:metadata>
#PostConstruct is run ONCE in first when Bean Created.
the solution is create a Unused property and Do your Action in Getter method of this property
and add this property to your .xhtml file like this :
<h:inputHidden value="#{loginBean.loginStatus}"/>
and in your bean code:
public void setLoginStatus(String loginStatus) {
this.loginStatus = loginStatus;
}
public String getLoginStatus() {
// Do your stuff here.
return loginStatus;
}
Calling bean action from a <p:remoteCommand> will be a good idea, keep attribute autoRun="true"
Example below
<p:remoteCommand autoRun="true" name="myRemoteCommand" action="#{bean.action}" partialSubmit="true" update=":form" />

JSF 2 invoke another bean in view and render their view

Following Example:
i have got three Beans:
GeneralBean
SpecificBean1
SpecificBean2
The view of the GeneralBean consists of an accordion that represents a list.
Now i would like to invoke the SpecificBean1 if a condition matches:
<c:if test="${condition==true}">
<ui:include src="SpecificBean1.xhtml" />
</c:if>
The above examples includes the view but does not invoke the bean in the background. Is it possible to achieve that? If yes, how?
So found out:
<c:if test="${condition==true}">
<ui:include src="/pages/SpecificBean1.xhtml">
<ui:param name="speacificBean" value="#{SpecificBean1}"></ui:param>
</ui:include>
</c:if>
*had a typo in the src path :/
to check this add a #PostConstruct annotated method containing a log-message to the specific bean.
#PostConstruct
public void init() {
log("Bean Created/Initialized");
}

PrettyFaces error with required attribute

I'm developing a web application using JSF 2 and prettyfaces. I annotated one of my #ViewScoped beans with pretty annotations. That's what I have:
#ManagedBean
#ViewScoped
#URLMapping(parentId = "app-list", id = "app-view", pattern = "/detail/#{appId}",
viewId = "/system/manage_app/content/app_detail/app_detail.xhtml")
public class NavegableAppView extends SystemNavegable {
/**
Basically that shows the details of an application which is installed in my system. This bean can be instanced in two ways, passing #{appId} param, which indicates the id of the application which I want to load, or without that param, in this case the bean will recover this id from a #SessionScoped bean.
That's how the page /system/manage_app/content/app_detail/app_detail.xhtml is managing the parameter:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
template="/templates/general_template.xhtml">
<ui:define name="metadata">
<f:metadata>
<f:viewParam id="appId" name="appId"
value="#{navegableAppView._ParamApp}" required="false" />
<f:event type="preRenderView"
listener="#{navegableAppView.initialize}" />
</f:metadata>
</ui:define>
<ui:define name="general_content">
<p:panel>
<!--More stuff-->
The problem here is I want NavegableAppView bean to be created, with or without param. I have tried this way <p:button value="prueba" outcome="pretty:app-view" /> which works but limits me to do nothing more than outcome and also <p:commandButton value="prueba2" action="pretty:app-view" ajax="false" />, which is the equivalent to call an action method and return the navigation case (that's what really I want).
First choice creates the bean properly and loads the value from the session. Second case, is giving me this error:
HTTP 500 - PrettyFaces: Exception occurred while building URL
for MappingId < app-view >, Required value < #{appId} > was null
So my target bean is not getting constructed. I have tried adding the parameter manually to the navigation case: return pretty:app-view?appId=1 and it works, but I want the target bean to recover it from the session itself. Do I have to call a redirect or something like that in my action method?
Pool your ideas.
So you are actually running into one of the "edge" effects of PrettyFaces. The "appId" parameter you have defined is actually treated both a parameter name, and also an EL bean value location for building links.
#URLMapping(parentId = "app-list", id = "app-view", pattern = "/detail/#{appId}",
viewId = "/system/manage_app/content/app_detail/app_detail.xhtml")
When you use the postback-action navigation functionality of PrettyFaces, it requires an EL bean name. Now, it just so happens that since you have not provided one in your #URLMapping annotation, that PrettyFaces is going to try to use the parameter name anyway, and hope that it can find what you want. In this case, obviously, there is no bean value called #{appId}.
You're really mixing two types of functionality that attempt to solve the same problem. Your <f:metadata> and <f:viewParam> definitions are doing the same thing that PrettyFaces does with its path-parameters and action methods. You should use one or the other mechanism. If you really want to mix them, then as you said, you should be invoking actual navigation from your <h:commandButton>, like so:
<p:commandButton value="prueba2" action="#{navegableAppView.goToAppId}" ajax="false" />
Then, you'll need to make sure you return a valid JSF2 navigation string WITH the appId parameter, such as:
public String goToAppId() {
return "/system/manage_app/content/app_detail/app_detail.xhtml?faces-redirect=true&appId=" + appId";
}
PrettyFaces will then understand that you are redirecting to a URL that has been mapped, and will perform outbound rewriting on the URL, and send you to the proper, /detail/#{addId} instead. This is all in the docs.
The final option would simply to remove the <f:metadata> and <f:viewParam>, and use the built-in PrettyFaces functionality for managing view parameters instead. Simply removing the metadata and updating your #URLMapping to this, would solve your problem:
#ManagedBean
#ViewScoped
#URLMapping(parentId = "app-list", id = "app-view", pattern = "/detail/#{appId : navegableAppView._ParamApp}",
viewId = "/system/manage_app/content/app_detail/app_detail.xhtml")
public class NavegableAppView extends SystemNavegable {
#URLAction
public String initialize() {
if ( appId != null ) {
this.item = appsDB.findById(appId);
return null;
}
// Add a message here, "The item {..} could not be found."
return "pretty:app-list";
}
This is how you initialize pages using PrettyFaces. When it comes down to it, if you are using pretty:mappingId navigation, you should only use PrettyFaces features. If you are going to use normal JSF2-style navigation where you specify the view-id and all the parameters of the URL, then you can mix-and match (as long as you are using named path-parameters in your URL mappings.
I hope this helps.

Can't use composite component on same page with a ui:include that relies on ui:params

I have a base page that uses a ui:include to include another page. The ui:include uses a ui:param to pass a parameter to the included page. The param is read in the PostConstruct method of the included page's controller.
This design works fine until I add a composite component to the base page; once added, the included page controller reports that the ui:param's value is null. Once I remove the composite component from the page, the ui:param is able to be read (i.e. is not null) by the included page's controller. Please help!
Files to reproduce the problem:
myPage.xhtml
<html xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:mycomponents="http://java.sun.com/jsf/composite/mycomponents">
<ui:include src="includePage.xhtml">
<ui:param name="myParam" value="myValue"/>
</ui:include>
<p/>
<mycomponents:myComponent/>
</html>
myIncludedPage.xhtml
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets">
The value of the param is: #{includedPageController.myParam}
</ui:composition>
myComponent.xhtml (placed in "resources/mycomponents")
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface/>
<composite:implementation>
I am the composite component
</composite:implementation>
</html>
IncludedPageController.java
#ManagedBean
public class IncludePageController
{
String myParam;
#PostConstruct
private void init()
{
FaceletContext faceletContext = (FaceletContext)FacesContext.getCurrentInstance().
getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
myParam = (String)faceletContext.getAttribute("myParam");
}
public String getMyParam()
{
return myParam;
}
public void setMyParam(String myParam)
{
this.myParam = myParam;
}
}
See: How do I set Managed Bean field to the value of a ui:param?. There is no standard for doing this sort of thing in the JSF API. A composite or custom component should be used rather than an include/param tag combination.

Resources