Generating a list of links to be displayed in Facelets - jsf

I need to have a list of links generated by JSF and displayed in Facelets. The bean would contain all of the links and where they need to point to, and then I assume some method would run to disperse all of them which could be called by some JSF attribute in the Facelets page.
I'm kind of clueless. How can I achieve this?

You can use ui:repeat tag:
<ui:repeat value="#{bean.links}" var="link" varStatus="status">
<h:outputLink value="#{link.url}">
<h:outputLabel value="#{link.name}"/>
</h:outputLink>
<h:outputText value=", " rendered="#{not status.last}"/>
</ui:repeat>
bean is managed bean that have getLinks method. getLinks method returns list of links. Every link is an object with name and url properties. All links are separated by commas.

Related

Dynamic id for primefaces datatable [duplicate]

I'm trying to assign an id to a component inside a <ui:repeat> like that:
<ui:repeat value="#{bean.columns}" var="column">
<h:panelGroup layout="block" id="column_#{column.id}"
styleClass="#{column.id} dashboard_column">
The thing is that #{column.id} value is being placed properly inside the styleClass value but its not being set inside the id attribute. All that is being set inside the id attribute is the automatically generated id by the JSF + my hard coded value column_.
If I remove the hard coded column_ I get an exception:
java.lang.IllegalArgumentException: component identifier must not be a zero-length String
at
Any Ideas?
This is not possible with a render-time tag such as <ui:repeat>. The <ui:repeat> will however by itself already ensure the uniqueness of the generated client ID by prepending it with the row index. So just remove the EL part from the ID attribute of the component.
<ui:repeat value="#{bean.columns}" var="column">
<h:panelGroup layout="block" id="column">
With a view build time tag such as <c:forEach> (which will basically generate multiple <h:panelGroup> components instead of only one which is rendered multiple times), it is possible to specify a dynamic ID like that.
<c:forEach items="#{bean.columns}" var="column">
<h:panelGroup layout="block" id="column_#{column.id}">
(you should only be well aware of how JSTL works in Facelets)
An alternative is to use a static <div> element instead of a JSF <h:panelGroup layout="block"> component.
<ui:repeat value="#{bean.columns}" var="column">
<div id="column_#{column.id}">
See also:
JSTL in JSF2 Facelets... makes sense?
JSF prefixes the id automatically. If you simply write id="column" the generated HTML will contain such identifiers:
myForm:0:column
myForm:1:column
myForm:2:column
and so on.
Anyway: Do never use JSTL tags (like c:foreach and c:if) in JSF templates. They cause random behaviour, very difficult to debug. And if they work, the slow down the application a lot.
Use ui:repeat for loops, and ui:fragment for conditional blocks. Note that there is no replacement for c:set, such a construct does not exist anymore in JSF 2.

JSF 2 ui:repeat h:form h:inputText

Iam iterate a list of objects with ui:repeat.
For each Object h:form, h:inputText (for order value) and the commandLink for adding the Item will be generated.
<ui:repeat var="article" value="#{someDataBean.myArrayList}">
<h:form>
Value: <h:inputText value="#{baskedBean.articleValue"} />
<h:commandLink value="add" action="#{baskedBean.addArticel(article)}" />
</h:form>
</ui:repeat>
Lets suppose we have only one article, the order value (baskedBean.articleValue) is submitted and setted correctly.
If we have more than one article in the ui:repeat value list, the submitted value isnt setted. Expect i use the last article.
It looks like, that the other h:inputText components (under the current) will overwrite the value (baskedBean.articleValue)
I tought, that i could handle the problem by sourrunding the related article h:input and commandLink components by a dedicated h:form (only for the article) but it didn't work.
Iam using mojarra 2.2.4 (and testet it also with 2.2.3)
thanks
thanks for your help

Trying to render a h:panelGroup outside ui:repeat with complicated structure

This is the general structure of the jsf page:
<ui:repeat id="repeater" varStatus="stat" >
<h:form id="the-form">
<h:panelGroup id="renderme">
<ui:repeat id="inner-repeater">
<h:commandButton>
<f:ajax render=":repeater:#{stat.index}:the-form:renderme">
</h:commandButton>
</ui:repeat>
</h:panelGroup>
</h:form>
</ui:repeat>
So.. the button here, when clicked, should cause the element renderme to be re-rendered.
In practice, I get "component with id ... not found" although when I look at the html page, the generated id is correct.
Moreover, I tried to use #{component.parent.parent.clientId} which produced the same id and still got the same error message from JSF.
Any idea on why this is failing?
Thanks!
This doesn't work for the simple reason because viewRoot.findComponent("repeater:0:the-form:renderme") as requested by <f:ajax render> doesn't return anything. Such a component does not exist in the component tree. This ID only exists in the generated HTML output. Instead, it's viewRoot.findComponent("repeater:the-form:renderme") which would return something, but this does in turn not exist in HTML DOM tree where JavaScript needs to do the update based on ajax response. Even then, this is not exactly what you need.
This is where JSTL can come to rescue. It's capable of dynamically building the JSF component tree and of dynamically assigning IDs to components generated in a loop:
<c:forEach ... varStatus="stat">
<h:form id="the-form_#{stat.index}">
<h:panelGroup id="renderme">
<ui:repeat id="inner-repeater" ...>
<h:commandButton ...>
<f:ajax render=":the-form_#{stat.index}:renderme">
</h:commandButton>
</ui:repeat>
</h:panelGroup>
</h:form>
</c:forEach>
This will only cause problems when you bind <c:forEach> value to a view scoped bean and you use Mojarra version older than 2.1.18. You'd need to upgrade to at least Mojarra 2.1.18 then.
See also:
JSTL in JSF2 Facelets... makes sense?

How can I set id of a component/tag inside ui:repeat

I'm trying to assign an id to a component inside a <ui:repeat> like that:
<ui:repeat value="#{bean.columns}" var="column">
<h:panelGroup layout="block" id="column_#{column.id}"
styleClass="#{column.id} dashboard_column">
The thing is that #{column.id} value is being placed properly inside the styleClass value but its not being set inside the id attribute. All that is being set inside the id attribute is the automatically generated id by the JSF + my hard coded value column_.
If I remove the hard coded column_ I get an exception:
java.lang.IllegalArgumentException: component identifier must not be a zero-length String
at
Any Ideas?
This is not possible with a render-time tag such as <ui:repeat>. The <ui:repeat> will however by itself already ensure the uniqueness of the generated client ID by prepending it with the row index. So just remove the EL part from the ID attribute of the component.
<ui:repeat value="#{bean.columns}" var="column">
<h:panelGroup layout="block" id="column">
With a view build time tag such as <c:forEach> (which will basically generate multiple <h:panelGroup> components instead of only one which is rendered multiple times), it is possible to specify a dynamic ID like that.
<c:forEach items="#{bean.columns}" var="column">
<h:panelGroup layout="block" id="column_#{column.id}">
(you should only be well aware of how JSTL works in Facelets)
An alternative is to use a static <div> element instead of a JSF <h:panelGroup layout="block"> component.
<ui:repeat value="#{bean.columns}" var="column">
<div id="column_#{column.id}">
See also:
JSTL in JSF2 Facelets... makes sense?
JSF prefixes the id automatically. If you simply write id="column" the generated HTML will contain such identifiers:
myForm:0:column
myForm:1:column
myForm:2:column
and so on.
Anyway: Do never use JSTL tags (like c:foreach and c:if) in JSF templates. They cause random behaviour, very difficult to debug. And if they work, the slow down the application a lot.
Use ui:repeat for loops, and ui:fragment for conditional blocks. Note that there is no replacement for c:set, such a construct does not exist anymore in JSF 2.

JSF2 and Spring Webflow (<h:commandLink> doesn't respond inside <ui:repeat> facelet tag)

i am trying to have a List of commandLink in every cell of dataTable.
this is small example explaining what i am trying to do
<h:form id="form1">
<p:dataTable id="doctorTable" var="doctor"
value="#{search.medecinsResult}" rowIndexVar="rowIndex">
<p:column headerText="#{search.headerDate[1]}">
<ui:repeat var="seance" value="#{search.column2[rowIndex]}">
<h:commandLink value="#{seance}" action="Reserver"
title="Réservez cette séance">
</h:commandLink>
<br />
</ui:repeat>
</p:column>
</p:datable>
</h:form>
And i define transition on the page viewState in my XML flow:
<view-state id="result">
<transition on="Reserver" to="next">
</transition>
</view-state>
the commandLink work fine outside repeat tag, but when its inside it just reload the webpage
i found JIRA issues for that, but it not resolved.
link to JIRA issue
if there is any workaround it will be great, thank's for your responses.
It's the <ui:repeat> which is the culprit. It doesn't work very well when nested in another repeating component. There are many related issues for that already, the JSF guys are working on that. The usual solution is to pick a "fullworthy" JSF UIData component instead, such as <h:dataTable>. Since you're already using PrimeFaces, I'd suggest to try <p:dataList> instead.

Resources