Reuse some .xhtml pages on a JSF primefaces application - jsf

I developing a simple application using JSF and PrimeFaces and here's a problem that I'm facing:
These are managed beans that have a Person property:
ClientBean
EmployeeBean
I have the person.xhtml that shows the data from a person. I include the person.xhtml on a client.xhtml and employee.xhtml. I need to create two person.xhtml because I'm using different beans. What I want to do is something like that:
<c:set var="person" value="clientBean.person" />
<ui:include src="person.xhtml"/>
<c:set var="person" value="employeeBean.person" />
<ui:include src="person.xhtml"/>
And in my person.xhtml I can use #{person.name} , #{person.dateOfBirth}.
I searched and use <c:set/> in JSF is wrong.
Anyone can help?

Pass it as <ui:param>.
<ui:include src="person.xhtml">
<ui:param name="person" value="#{clientBean.person}" />
</ui:include>
<ui:include src="person.xhtml">
<ui:param name="person" value="#{employeeBean.person}" />
</ui:include>
Register person.xhtml if necessary as a tag file to make it look better, see also When to use <ui:include>, tag files, composite components and/or custom components?
<my:personForm value="#{clientBean.person}" />
<my:personForm value="#{employeeBean.person}" />
Beware of duplicate component ID errors. See also Avoiding duplicate ids when reusing facelets compositions in the same naming container.

Related

Every include should refer to other instance

I include a part of the XHTML page to my Web Application. This part can be included multiple times. And that's the problem! Because every include refers to the same java object. That means that every element has the same value. But I want for each include a new Java object. So whats the best way to solve this problem?
Main page with includes:
<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>
includAbleEditor.xhtml
<h:commandButton value="#{editorVisibility.evb.value}"
action="#{editorVisibility.evb.toggle}" />
<h:inputTextarea rendered="#{editorVisibility.evb.enabled}" />
This <h:inputTextarea> is an example for my problem. Every included inputTextarea has a toggle button. By clicking the button the textarea should be shown or hidden. But because of the same reference of the boolean value all <h:inputTextarea> will always have the same rendered value.
Do you have any suggestions?
Thanks a lot!
You'll have to hold as many instances of editorVisibility.evb as you have editors. You could for example create a List<TypeOfEvb> evbList in your EditorVisibility bean, and pass only one element to the <ui:include> as a <ui:param>:
Main page
<ui:include src="include/includeAbleEditor.xhtml">
<ui:param name="includeParam" value="MyClass" />
<ui:param name="evb" value="#{editorVisibility.evbList[0]}" />
</ui:include>
includAbleEditor.xhtml
<h:commandButton value="#{evb.value}"
action="#{evb.toggle}" />
<h:inputTextarea rendered="#{evb.enabled}" />
You could also create a composite component.
See also:
http://www.mkyong.com/jsf2/composite-components-in-jsf-2-0/

Dynamic ui:include in JSF

I have this code in JSF:
<ui:include rendered="#{paginaMB.pagina eq 'login'}" id="paginaSistema" src="/login.xhtml" />
<ui:include rendered="#{paginaMB.pagina eq 'noticias'}" id="paginaSistema" src="/noticias.xhtml" />
I don't know why using "rendered" both pages are displayed.
If I use this code:
<ui:include id="paginaSistema" src="#{paginaMB.pagina}.xhtml" />
the problem was solved but I have a button inside login.xhtml that uses managed bean and the managed bean is not found, no action is taken when I click on it.
How can I solve this dynamic include?
ui:include doesn't have attribute rendered
You should use ui:fragment.
<ui:fragment rendered="#{paginaMB.pagina eq 'login'}">
<ui:include id="paginaSistema" src="/login.xhtml" />
</ui:fragment>

Passing EL method expression as attribute of custom Facelets tagfile

I created a custom JSF tag:
<ui:composition>
<h:panelGroup>
<rich:dataScroller id="#{id}" for="#{table}" execute="#{table}"
page="#{scrollerPage}" render="#{table}-sc1" maxPages="5"
fastControls="hide" oncomplete="#{onCompl}" scrollListener="#{scrollListenerBean[scrollListenerMethod]}" />
<h:inputText value="#{scrollerPage}" id="#{table}-sc1" size="2">
<f:convertNumber integerOnly="true" />
</h:inputText>
<h:outputText styleClass="outputText"
value=" of #{scrollPagesCount} " />
<h:commandButton value="GO! " />
</h:panelGroup>
</ui:composition>
To pass the listener method, I used the solution suggested in a quite old blog:
<my:dataScroller id="idDS1" table="table1"
scrollerPage="#{bean.navigationHelper.scrollerPage}"
scrollPagesCount="#{bean.navigationHelper.scrollPagesCount}"
onCompl="initForm();"
scrollListenerBean="#{bean}"
scrollListenerMethod="aMethod" />
My questions are: is this the best way to do this? How can I make the method optional?
Thanks a lot for any Help! bye!
My questions are: is this the best way to do this?
That's the only way anyway, provided that you can only use standard JSF/EL facilities and you cannot create a custom taghandler.
You could however create a custom taghandler to convert the value expression to a method expression. The OmniFaces JSF utility library has a <o:methodParam> for exactly this purpose. See also the <o:methodParam> demo page.
You could then end up like:
<my:dataScroller ... scrollListener="#{bean.aMethod}" />
and
<o:methodParam name="scrollListenerMethod" value="#{scrollListener}" />
<rich:dataScroller ... scrollListener="#{scrollListenerMethod}" />
See also:
Dynamic ui include and commandButton
How can I make the method optional?
Theoretically, you could use JSTL tags to build the view conditionally. Something like:
<h:someComponent>
<c:if test="#{not empty fooAttribute}">
<f:attribute name="foo" value="#{fooAttriubte}" />
</c:if>
</h:someComponent>
But that's in the particular case of a special method expression listener attribute unfortunately not possible. There's no such thing as <rich:scrollListener> or something which allows you binding a RichFaces specific scrollListener as a separate tag to the <rich:dataScroller>. Best what you could do without creating custom taghandlers is duplicating the whole <rich:dataScroller> in two <c:if>s (or a <c:choose>); one with and other without scrollListener. This is too clumsy. You'd really better create a custom <my:richScrollListener> taghandler for this which you could then place in a <c:if>.

Parameterization of facelet custom tag

I have created facelet template:
left-right.xhtml
<ui:composition>
<ui:include name="left" />
<hr />
<ui:include name="right" />
</ui:composition>
After, if I use this template with ui:decorate it works fine:
index.xhtml
<ui:decorate template="left-right.xhtml">
<ui:define name="left">FOO</ui:define>
<ui:define name="right">BAR</ui:define>
</ui:decorate>
BUT, if I use this template as custom facelet tag it does not works.
custom-taglib.xml
<facelet-taglib>
<tag>
<tag-name>leftright</tag-name>
<source>left-right.xhtml</source>
</tag>
</facelet-taglib>
index.xhtml
<custom:leftright>
<ui:define name="left">FOO</ui:define>
<ui:define name="right">BAR</ui:define>
</custom:leftright>
The content inside ui:define tags is not included into template :(
So, question is how can I parameterise facelet template if it renders as facelet custom tag?
(note that you have a syntax error in your left-right.xhtml, you should be using <ui:insert> instead of <ui:include>, but I'll assume it to be just careless oversimplification)
A tag file cannot be treated as a template client. You need to approach it differently depending on the concrete functional requirement. If you're on JSF 2.x, then a composite component would be the closest which you need. You could define the parts as <f:facet> and render them by <cc:renderFacet> in the composite implementation.
E.g.
/resources/custom/leftRight.xhtml
<cc:interface>
<cc:facet name="left" required="true" />
<cc:facet name="right" required="true" />
</cc:interface>
<cc:implementation>
<cc:renderFacet name="left" />
<hr />
<cc:renderFacet name="right" />
</cc:implementation>
Usage:
<custom:leftRight>
<f:facet name="left">FOO</f:facet>
<f:facet name="right">FOO</f:facet>
</custom:leftRight>
But if you're still on JSF 1.x, you cannot create a composite component. You'd need to stick to <ui:decorate>.
See also:
When to use <ui:include>, tag files, composite components and/or custom components?

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]}" />

Resources