How to use <ui:repeat> to iterate over a nested list? - jsf

Using JSF 2.0, I need to display a table wherein each row contains a link which opens a popup. I have two models: A which has id and List<B> properties and B which has id and name properties. In my backing bean, I have a List<A> property. In my view, I am using <ui:repeat> to iterate over List<A>.
The requirement is, depending on the row that the user clicks, the corresponding List<B> of A needs to be displayed. However, the <ui:repeat> does not accept a nested list to be assigned in the var attribute. Hence, I need to do a lot of workarounds which is not efficient.
How do I efficiently solve this problem?

What you need is to nest another <ui:repeat> tag in your outer iteration:
<ui:repeat value="#{bean.listOfA}" var="a">
...
<ui:repeat value="#{a.listOfB}" var="b">
...
</ui:repeat>
</ui:repeat>
The only thing left that is worth noting is that nested <ui:repeat> tags used to have problems with state management until Mojarra 2.1.15 version (details in jsf listener not called inside nested ui:repeat and in many not so recent questions and their answers), which could result in action listeners not called, etc. but if you're currently on the latest Mojarra JSF implementation - just skip this part altogether.

Related

Missing parameter values in invoked method with composite components using ui:repeat

So after several days of debugging, we were eventually able to reproduce some strange interactions between composite components, ui:repeat, p:remoteCommand and partial state saving in JSF that we do not understand.
Scenario
A composite component iterates over a list of objects using ui:repeat. During each iteration, another composite component is included and arguments are passed.
<ui:composition (...)>
<ui:repeat var="myVar" value="#{cc.attrs.controller.someList}">
<namespace:myRemoteCommand someParam="SomeParam"/>
In the included composite component, there is an auto-run p:remoteCommand calling a method using parameters defined in the component's interface.
<ui:component (...)>
<p:remoteCommand actionListener="#{someBean.someMethod(cc.attrs.someParam)}"
autoRun="true"
async="true"
global="false">
However, when setting a breakpoint in someMethod(...), an empty string is passed. This only happens if partial state saving is set to false.
Solutions
We tried several solutions and the following ones appear to work (however we do not understand why and cannot foresee any further problems that could occur):
We can set partial state saving to true.
We can change the composite component pattern to ui:include.
We can remove one or both of the composite components and directly include the content instead.
Question
Why does JSF behave this way? What is this interaction between composite component, ui:repeat and argument passing that changes depending on whether we use ui:include / partial state saving or not?
We're using Primefaces 5.3, Glassfish 4.1, Mojarra 2.2.12, Java 8.
Your code is all fine. It's just that Mojarra's <ui:repeat> is broken. You're not the first one facing a state management related problem with <ui:repeat>.
Checkbox inside ui:repeat not refreshed by Ajax
Dynamically added input field in ui:repeat is not processed during form submit
Components are with the same id inside ui:repeat
<h:form> within <ui:repeat> not entirely working, only the last <h:form> is processed
Composite component with custom backing component breaks strangely when nested inside ui:repeat
ui:repeat in o:tree not working as expected
Root cause of your problem is that #{cc} is nowhere available at the moment the <ui:repeat> needs to visit the tree. Effectively, the <ui:repeat value> is null. A quick work around is to explicitly push the #{cc} in UIRepeat#visitTree() method. Given Mojarra 2.2.12, add below lines right before line 734 with pushComponentToEL(facesContext, null).
UIComponent compositeParent = getCompositeComponentParent(this);
if (compositeParent != null) {
compositeParent.pushComponentToEL(facesContext, null);
}
And add below lines right after line 767 with popComponentFromEL(facesContext).
if (compositeParent != null) {
compositeParent.popComponentFromEL(facesContext);
}
If you don't build Mojarra from source, copy the entire source code of UIRepeat into your project, maintaining its package structure and apply above changes on it. Classes in /WEB-INF/classes have higher classloading precedence than those in /WEB-INF/lib and server's /lib. I have at least created issue 4162 to address this.
An alternative is to replace Mojarra by MyFaces, or to replace the <ui:repeat> by an UIData based component which got state management right such as <h:dataTable> or <p:dataList>.
<p:dataList type="none" var="myVar" value="#{cc.attrs.controller.someList}">
<namespace:myRemoteCommand someParam="SomeParam" />
</p:dataList>
You might only want to apply some CSS to get rid of widget style (border and such), but that's trivial.
See also:
Should PARTIAL_STATE_SAVING be set to false?

Set ID from backing bean in JSF

Is this legal?
<h:form id="status${a.myID}" >
// ...
</h:form>
where 'a' is an object in a backing bean. It seems to sort of work, but when I look at the rendered HTML, I see the id as: :0:status for example, instead of :status0 as I would expect. My main problem is trying to reference the id from <f:ajax render=.... I'm getting "contains an unknown id..." with pretty much every combination I can think of. Is it possible to set ids using values from a backing bean reliably?
The single-letter variable name ${a} and the symptom of an iteration index like :0 being auto-appended in client ID, suggests that this <h:form> is inside a JSF iterating component such as <h:dataTable> or <ui:repeat> with a var="a" which actually is not a backing bean. It would confirm and explain all symptoms described so far. If ${a} were a real backing bean (and not an iteration variable), then it would have "worked" and you would have seen :0:status0, :1:status0, :2:status0, etc — whose usefulness is questionable though.
First of all, the id attribute of a JSF component is evaluated and set during view build time, the moment when the JSF component tree is to be built based on XHTML source code file. The var attribue of a JSF iterating component is set during view render time, the moment when the HTML output is to be generated based on JSF component tree. Thus, logical consequence is, the object set by var attribute is not available at the moment the id attribute needs to be set and thus evaluates to null/empty-string. The effect is exactly the same as when you would do
<h:form id="status">
JSF iterating components namely already auto-appends the iteration index to the generated client ID. It would not make any sense to manually set the ID of the iterated item in the component ID. There's namely physically only one <h:form> component in the JSF component tree which is in turn reused multiple times during producing the HTML output based on the current iteration round.
This Q&A should also give more food for thought: JSTL in JSF2 Facelets... makes sense?
Coming back to your concrete functional requirement of referencing a component in <f:ajax render>, you definitely need to solve this differently. Unfortunately you didn't clearly describe the context of the source component and the target component, so it's impossible to give/explain the right client ID and so I'm just giving you a link so that you can figure it out on your own: How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
Unrelated to the concrete problem, the old JSP EL style ${...} has in Facelets exactly the same effect as #{...}. In order to avoid confusion by yourself and your future maintainers it's recommend to completely ban usage of ${...} and stick to #{...} all the time. See also Difference between JSP EL, JSF EL and Unified EL
Actually ${a.myID} this is not rendering any output. As you are getting :0:status as form ID which implies, :0 is parent of :status in HTML tree structure.

Naming Container in JSF2/PrimeFaces [duplicate]

This question already has answers here:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
(6 answers)
Closed 6 years ago.
What are the possible naming containers in PrimeFaces? Why it is necessary to append naming container id for Ajax update call when we want to update some UI control on form using update=":mainForm:MainAccordian:userNameTextbox"?
What are the possible naming container in Prime faces
In JSF naming containers derive from UINamingContainer.
why it is necessary to append naming container id for Ajax update call when we want to update some UI control on form using update=":mainForm:MainAccordian:userNameTextbox"
Lets say, <h:outputText value="test1" id="userNameTextbox" /> and you add another <h:outputText value="test2" id="userNameTextbox" /> to your page, you will get an error which says that you have a duplicate ID. You can look it up here at the JavaDoc for UIComponent.setId(String):
Set the component identifier of this UIComponent (if any). Component identifiers must obey the following syntax restrictions:
Must not be a zero-length String.
First character must be a letter or an underscore ('').
Subsequent characters must be a letter, a digit, an underscore (''), or a dash ('-').
.. furthermore, important for you:
The specified identifier must be unique among all the components (including facets) that are descendents of the nearest ancestor UIComponent that is a NamingContainer, or within the scope of the entire component tree if there is no such ancestor that is a NamingContainer.
Means that you cannot have two components with the same ID under the same NamingContainer (if you have no NamingContainer at all, the entire tree is counted as NamingContainer).
Therefore you need to add a NamingContainer, like a <h:form id="myNamingContainer" />
Lets take following example:
<h:outputText value="test1" id="userNameTextbox" />
<h:form id="container1">
<h:outputText value="test2" id="userNameTextbox" />
</h:form>
<h:form id="container2">
<h:outputText value="test3" id="userNameTextbox" />
</h:form>
.. and you want to do an update to userNameTextbox. Which userNameTextbox are you refering to because there are 3?
The first one? Then update userNameTextbox
The second one? Then update container1:userNameTextbox
The third one? Then update container2:userNameTextbox
After having IntelliJ scan all my JARs for implementations of javax.faces.component.NamingContainer here is what I found:
From PrimeFaces 5.3
AccordionPanel
Carousel
Columns
DataGrid
DataList
DataScroller
DataTable
Page
Ring
SubTable
Subview
TabView
TreeTable
UIData
UITabPanel
From MyFaces 2.1
HtmlDataTable
HtmlForm
UITree
UIForm
Naming Containers in Prime Faces
As we can see in JSF Reference
NamingContainer is an interface that must be implemented by any UIComponent that wants to be a naming container. Naming containers affect the behavior of the UIComponent.findComponent(java.lang.String) and UIComponent.getClientId() methods;
So to find Naming Containers in PF you need to check hierarchy of NamingContainer interface. In Eclipse you can do this for example by Ctrl+T shortcut on NamingContainer.
In PF 5.3 there are for example: AccordionPanel, Carousel, Columns, DataGrid, DataList, DataScroller, DataTable, Ring, SubTable, TabView, Tree, TreeTable.
Naming Container influence on component id
Default behavior
Naming Container provide a naming scope for its child components. So it always add prefix to his children id. So id of child component is: parent_component_id".concat(":").concat("component_id").
There is one pro tip that I had read in JavaServer Faces 2.0, The Complete Reference that even if you not add NamingContainer to your page it is always automatically added by JSF itself :) There also exist special algorith of this creation (Chapter 11: Building Custom UI Component -> Box called "Rules for Creating the Top-Level Component for a Composite Component"). Of course when you don't set id, it will be generate automatically (for example j_idt234). So full component id may look like this: "j_idt123:j_idt234:j_idt345".
Change component name separator (since JSF 2.x)
There is a way to override default component name separator (":"). You can define it in web.xml as context-param with name javax.faces.SEPARATOR_CHAR. For example:
<context-param>
<param-name>javax.faces.SEPARATOR_CHAR</param-name>
<param-value>-</param-value>
</context-param>
UIForm attribute "prependId"
To avoid adding scope to child component there is an attribute (only in UIForm component). But this is not recommended solution. Take a look for example at
uiform-with-prependid-false-breaks-fajax-render
Component id usage (for example in "update", "process")
Whole id
You can use whole id: "componentParent:component". This is not recommended (code will be fragile; any id changes will cause need to change ids in many places).
Relative ids in same level of naming container
Inside one naming container you can use simple component id.
PrimeFaces Search Expression Framework
If you don't know this feature please take a look in PrimeFaces documentation. Prime Faces provide Search Expression Framework with couple of very usefull mechanism.
You can search by keywords.
Keywords are the easier way to reference components, they resolve to
ids so that if an id changes, the reference does not need to change.
Core JSF provides a couple of keywords and PrimeFaces provides more
along with composite expression support.
Examples: #this (current component), #form (closest ancestor form), #namingcontainer (closest ancestor naming container), #parent, #widgetVar(name).
You can also mixed those keywords in quite complex paths (Composite Expressions) for example: #form:#parent, #this:#parent:#parent
The second posibility PF gives you are PrimeFaces Selectors (PFS).
PFS integrates jQuery Selector API with JSF component referencing
model so that referencing can be done using jQuery Selector API
instead of core id based JSF model.
So you can for example:
update all form elements by update="#(form)"
update all datatables by update="#(.ui-datatable)"
update all components that has styleClass named "myStyle" by update="#(.myStyle)"
Quite a powerful tool.

How to use <ui:include> inside a <h:dataTable>?

I want to inlude <ui:include> one page dynamically several times.
Code:
<h:dataTable ..>
<h:column>
<ui:include src="#{create_page}">
<h:column>
<h:dataTable>
Now when I submit it persists only the last inlude. It remembers only the values for the last included page. I want unique entity object in each create_page. How can I do that?
The <ui:include> is as being a tag handler executed during view build time, while the <h:dataTable> is as being an UI component executed during view render time. This means that the <ui:include> is executed only once before the <h:dataTable> and thus not during the iteration. You effectively end up with exactly the same include source in every row. When the form is submitted the rows are processed one by one until the last row, that's why you effectively end up with the values of the last row.
There are basically 2 ways to solve this:
Use <c:forEach> instead of <h:dataTable>, this runs also during view build time.
Use a tag file or a composite component instead of <ui:include>, this runs also during view render time.
Either way, you also need to ensure that the input values are bound to the object behind the var attribute of the datatable, not to one and same backing bean property.
See also:
JSTL in JSF2 Facelets... makes sense? (the <ui:include> falls in the same category as JSTL)
When to use <ui:include>, tag files, composite components and/or custom components?

JSF Required=Yes not working inside a datatable?

I searched everywhere but could not find a solution to this. I am trying to used
required=yes to validate whether a value is present or not. I am using it inside inputtext.
The problem is it does not work inside a datatable. If I put the text box outside the datatable it works. I am using JSF 1.7 so I don't have the validateRequired tag from JSF 2.0.
I even used a validator class but it is still not working. Does anyone know why does required=yes or validator='validationClass' inside a inputtext inside a datatable is not working.
I appreciate the help.
Thanks.
First of all, the proper attribute values of the required attribute are the boolean values true or false, not a string value of Yes. It's an attribute which accepts a boolean expression.
The following are proper usage examples:
<h:inputText required="true" />
<h:inputText required="#{bean.booleanValue}" />
<h:inputText required="#{bean.stringValue == 'Yes'}" />
As to the problem that it doesn't work inside a <h:dataTable>, that can happen when the datamodel is not been preserved properly (the datamodel is whatever the table retrieves in its value attribute). That can in turn happen when the managed bean is request scoped and doesn't prepare the datamodel during its (post)construction which causes that the datamodel is null or empty while JSF is about to gather, convert and validate the submitted values.
You need to ensure that the datamodel is exactly the same during the apply request values phase of the form submit request as it was during the render response phase of the initial request to display the form with the table. An easy quick test is to put the bean in the session scope. If that fixes the problem, then you definitely need to rewrite the datamodel preserving logic. You could also use Tomahawk's <t:saveState> or <t:dataTable preserveDataModel="true"> to store the datamodel in the view scope (like as JSF2's new view scope is doing).
Finally, JSF 1.7 doesn't exist. Perhaps you mean JSF 1.2?

Resources