JSF 1.2: dynamic <ui:param /> - jsf

There are some answers on stackoverflow, but no one fits my needs :(
I'm trying to conditionally build a <ui:param /> for my parent template with JSTL. Something like this:
<ui:composition ... template="template.xhtml">
<c:if test="#{condition}">
<ui:param name="parameter" value="parameterValue" />
</c:if>
<ui:define name="insertName">
{...}
</ui:define>
</ui:composition>
I tried with both namespaces for JSTL: http://java.sun.com/jstl/core and http://java.sun.com/jsp/jstl/core, but neither achieves the wanted behaviour. What should I do?
Funny thing, http://java.sun.com/jstl/core works like it should but INSIDE the <ui:define ...>
Im working with JSF 1.2 on WebLogic 7.

Related

Consolidate several trivial JSF Views

I'm new to JSF, so please forgive me if I'm asking a stupid question.
Suppose I have a common.xhtml file that can be reused by several screens. In fact, the only difference between the screens is the backing bean. For example:
URL: ~/person
<ui:composition template="common.xhtml">
<ui:param name="bean" value="#{personBean}" />
</ui:composition>
URL: ~/vehicle
<ui:composition template="common.xhtml">
<ui:param name="bean" value="#{vehicleBean}" />
</ui:composition>
URL: ~/location
<ui:composition template="common.xhtml">
<ui:param name="bean" value="#{locationBean}" />
</ui:composition>
URL: ~/food
<ui:composition template="common.xhtml">
<ui:param name="bean" value="#{foodBean}" />
</ui:composition>
etc...
Is there a way I can avoid creating all of these trivial xhtml files? Can I somehow dynamically set the backing bean and just point each of these URLs directly to the common.xhtml file?

How can I switch between two ui:compositions in a Facelets file?

In a JSF xhtml file, I would like to be able to choose between two different ui:compositions based on some flag. This is illustrated below using a fictional magic:if tag. How can I do this? In other words, what real tag can I use in place of magic:if?
<magic:if test="showOption1">
<ui:composition template="/option1.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:composition>
</magic:if>
<magic:if test="!showOption1">
<ui:composition template="/option2.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:composition>
</magic:if>
In other words, what real tag can I use in place of magic:if?
There's none. The <ui:composition> is the root element. Nothing can end up higher.
You have 2 options:
Do the switch in template attribute itself.
<ui:composition template="/option#{showOption1 ? 1 : 2}.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:composition>
Use <ui:decorate> inside <ui:composition> instead, this one can be wrapped in a <c:if>.
<ui:composition template="/options.xhtml">
<c:if test="#{showOption1}">
<ui:decorate template="/option1.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:decorate>
</c:if>
<c:if test="#{not showOption1}">
<ui:decorate template="/option2.xhtml">
<ui:define name="header">Foo</ui:define>
</ui:decorate>
</c:if>
</ui:composition>

What is the real conceptual difference between ui:decorate and ui:include?

It occurs ago me that ui:decorate is functionally the same as ui:include except that you can also pass ui:param and ui:define to the included file.
Am I crazy?
EDIT : Although in fact you can pass ui:param to a ui:include file too, it turns out I am already doing it. Maybe you can pass a ui:define as well, I will check and edit here.
The main difference between <ui:include> and <ui:decorate> is that the <ui:decorate> is intended to allow insertion of user-defined template components, while the <ui:include> is intended to include an existing and already-predefined template.
This indeed means that the <ui:decorate> supports <ui:define> for user-defined template components in its body and can insert it at the <ui:insert> place inside the template.
Here's a -somewhat clumsy- example to show where it can be used:
/WEB-INF/templates/field.xhtml
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:outputLabel for="#{id}" value="#{label}" />
<ui:insert name="input" />
<h:message id="#{id}_message" for="#{id}" />
</ui:composition>
/page.xhtml
<h:panelGrid columns="3">
<ui:decorate template="/WEB-INF/templates/field.xhtml">
<ui:param name="label" value="Foo" />
<ui:param name="id" value="foo" />
<ui:define name="input">
<h:inputText id="foo" value="#{bean.foo}" required="true" />
</ui:define>
</ui:decorate>
<ui:decorate template="/WEB-INF/templates/field.xhtml">
<ui:param name="label" value="Bar" />
<ui:param name="id" value="bar" />
<ui:define name="input">
<h:selectBooleanCheckbox id="bar" value="#{bean.bar}" required="true" />
</ui:define>
</ui:decorate>
...
</h:panelGrid>
Note that it renders the components nicely in each cell of the panel grid. Again, this particular example is pretty clumsy, I'd just have used a tag file instead. Only if it was a larger section, e.g. a whole form whose e.g. its header or footer should be customizable, then an <ui:decorate> would have been appropriate.
Another major advantage of <ui:decorate> is that it allows you to use a composite component with a template. See also Is it possible to use template with composite component in JSF 2?

How to use ui:include with parameters?

Have JSF 1.2 two pages(one.xhtml and other.xhtml), that are included to the current page by following rule:
...
<c:if test="#{flowScope.Bean.param1}">
<ui:include src="one.xhtml"/>
</c:if>
<c:if test="#{!flowScope.Bean.param1}">
<ui:include src="other.xhtml"/>
</c:if>
...
As far one.xhtml differs from other.xhtml only by action parameters:
one.xhtml:<h:commandLink action="actionOne">
other.xhtml:<h:commandLink action="actionTwo">
Is it possible to use some general xhtml? Instead of one.xhtml and other.xhtml,something like this:
...
<c:if test="#{flowScope.Bean.param1}">
<ui:include src="general.xhtml" param="actionOne"/>
</c:if>
<c:if test="#{!flowScope.Bean.param1}">
<ui:include src="general.xhtml" param="actionTwo"/>
</c:if>
...
thank you for help.
You need to nest <ui:param> inside <ui:include> to pass parameters to the included file.
<ui:include src="general.xhtml">
<ui:param name="action" value="actionOne" />
</ui:include>
and in the include:
<h:commandButton action="#{action}" />
Note that this only supports strings, not action methods. For the latter you would need to upgrade to JSF 2.0 and use composite components.
In addition to BalusC's answer:
Note that this only supports strings,
not action methods. For the latter you
would need to upgrade to JSF 2.0 and
use composite components.
There is a way to do this with JSF 1.2, though it's somewhat ugly:
<ui:include src="general.xhtml">
<ui:param name="actionBean" value="#{myBackingBean}" />
<ui:param name="actionMethod" value="edit" />
</ui:include>
and
<h:commandButton action="#{actionBean[actionMethod]}" />

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