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");
}
Related
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)
I have a p:commandLink in my xhtml with the value toggling between "Show"/"Hide".
Is there any way by which I can get the value of this commandlink from the backing bean?
I mean, I want to know what value the command link is showing currently i.e. Show/Hide?
To the point, the invoking component is just available in ActionEvent argument:
<h:commandLink id="show" value="Show it" actionListener="#{bean.toggle}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.toggle}" />
with
public void toggle(ActionEvent event) {
UIComponent component = event.getComponent();
String value = (String) component.getAttributes().get("value");
// ...
}
However, this is a poor design. Localizable text should absolutely not be used as part of business logic.
Rather, either hook on component ID:
String id = (String) component.getId();
or pass a method argument (EL 2.2 or JBoss EL required):
<h:commandLink id="show" value="Show it" actionListener="#{bean.toggle(true)}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.toggle(false)}" />
with
public void toggle(boolean show) {
this.show = show;
}
or even just call the setter method directly without the need for an additional action listener method:
<h:commandLink id="show" value="Show it" actionListener="#{bean.setShow(true)}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.setShow(false)}" />
As #BalusC suggested, your approach is not a good solution. But if you really want to do that, you can bind the component (p:commandLink) to your backingbean, as seen in What is the advantages of using binding attribute in JSF?.
After the component was bound, you can access the value attribute from the p:commandLink.
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;
}}
The use case is calling a method on a JSF 2.x Backing Bean directly from a hyperlink (Non-Faces-Request). What is the best way to do this?
I imagine to do something like this:
The Link:
http://localhost/show.xhtml?id=30&backingbeanname=loaddata&method=load
The Backing Bean:
#Named (value = "loaddata")
public class DataLoader {
public void load(int id){ ... }
}
Use <f:viewParam> in the target view to set GET parameters as bean properties and use <f:event type="preRenderView"> to invoke an action on them.
In show.xhtml:
<f:metadata>
<f:viewParam name="id" value="#{bean.id}" required="true" />
<f:event type="preRenderView" listener="#{bean.load}" />
</f:metadata>
<h:message for="id" />
In managed bean:
private Integer id;
private Data data;
public void load() {
data = service.find(id);
}
Note that in the above example the URL http://localhost/show.xhtml?id=30 is sufficient. You can always set more parameters as bean properties and have one "God" bean which delegates everything, but that's after all likely clumsy.
Also note that you can just attach a Converter to the <f:viewParam> (like as you could do in <h:inputText>). The load() method is then most likely entirely superfluous.
<f:metadata>
<f:viewParam name="id" value="#{bean.data}"
converter="dataConverter" converterMessage="Bad request. Unknown data."
required="true" requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:message for="id" />
See also:
Communication in JSF 2 - Processing GET request parameters
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
in a way similar to here I am using an abstract class to type the item set list
of ui:repeat. Concrete subclasses override the getType() method, that is used to
conditionally render the respective subtype with its particular properties:
<!-- AbstractAction Rule#getActions() -->
<ui:repeat value="#{rule.actions}" var="action">
<!-- render when "action" instance of NotificationAction -->
<h:panelGroup rendered="#{action.type == 'notification'}">
... UI for NotificationAction properties
<h:panelGroup rendered="#{action.type == 'callback'}">
...
When run on Glassfish 3 there is an error about properties not being defined on list
members of other subclasses (PropertyNotFoundException), which occurs in a branch that
is actually switched off by the rendered property. c:forEach/c:choose do not seem
appropriate. Any ideas how to make the rendering really conditional and bypass the
property checking are highly appreciated!
Thank you.
Jaro
after some testing it turned out, that the ui:repeat component itself caused the error.
Despite being in the final RenderResponse phase it tries to save the status of its child input components. Here a shortened exception dump:
Caused by: javax.el.PropertyNotFoundException: ... The class FOO does not have a readable property 'BAR'.
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:104)
at com.sun.faces.facelets.component.UIRepeat.saveChildState(UIRepeat.java:343)
at com.sun.faces.facelets.component.UIRepeat.setIndex(UIRepeat.java:428)
at com.sun.faces.facelets.component.UIRepeat.process(UIRepeat.java:522)
at com.sun.faces.facelets.component.UIRepeat.encodeChildren(UIRepeat.java:926)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1613)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:273)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:127)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
Hereby the rendered condition is ignored and the EL interpreter complains about non-existent properties. There is a simple solution by using the h:dataTable iterator with a single column instead:
<h:dataTable value="#{rule.systemActions}" var="action">
<c:set var="name" value="#{action.class.simpleName.toLowerCase()}" />
<h:column>
<h:panelGroup rendered="#{name == 'notification'}">
<h:outputLabel for="phone">Phone:</h:outputLabel>
<h:inputText value="#{action.phone}" id="phone" />
</h:panelGroup>
<h:panelGroup rendered="#{name == 'reminder'}">
...
</h:panelGroup>
</h:column>
</h:dataTable>
Cheers.
Jaro