Issue Details (XML | Word | Printable)

Key: JAVASERVERFACES-1817
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Critical Critical
Assignee: rogerk
Reporter: Mathias Werlitz
Votes: 22
Watchers: 17
Operations

If you were logged in you would be able to see more operations.
javaserverfaces

<f:ajax> does not work in nested <ui:repeat>

Created: 24/Sep/10 05:46 AM   Updated: 30/Oct/12 01:54 PM   Resolved: 30/Oct/12 01:54 PM
Component/s: ajax
Affects Version/s: 2.0.3
Fix Version/s: 2.1.15, 2.2.0-m06

Time Tracking:
Not Specified

File Attachments: 1. Zip Archive 1817.zip (7 kB) 10/Mar/11 08:42 AM - Mathias Werlitz
2. Text File changebundle-1817.txt (14 kB) 30/Oct/12 01:38 PM - rogerk
3. Zip Archive errorDemo.zip (20 kB) 11/Oct/12 05:59 PM - n.lundquist
4. Zip Archive new example.zip (1.27 MB) 17/Feb/11 09:14 AM - adriaaaaan
5. Zip Archive WebApplication1.zip (2.04 MB) 17/Feb/11 07:26 AM - adriaaaaan

Environment:

Operating System: All
Platform: All


Issuezilla Id: 1,817
Status Whiteboard:

size_medium importance_medium

Tags: ajax
Participants: adriaaaaan, knob_creek, Marcel Kolsteren, Mathias Werlitz, n.lundquist, rogerk and sinixtek


 Description  « Hide

The action of a commandLink is not called via ajax when it is located in a
double nested <ui:repeat>. It works in a non-nested <ui:repeat>. Using a double
nested <h:dataTable> works instead.

Example:
<ui:repeat var="items" value="#{someBean.items}">
<ui:repeat var="subitem" value="#{item.subitems}">
<h:commandLink action="#{subitem.action}">
<f:ajax />
</h:commandLink>
</ui:repeat>
</ui:repeat>



adriaaaaan added a comment - 18/Jan/11 06:51 AM - edited

Adding my vote to this issue, both our results display and our dashboard depend on double nested ui:repeats. This is a regression, it works in 2.0.2. We use gf3.0.1 in production and cannot upgrade to gf3.1 if this isn't resolved.


rogerk added a comment - 19/Jan/11 07:35 AM

triage


rogerk added a comment - 11/Feb/11 01:05 PM

I have this similar example and it works:

<ui:repeat value="#{repeatBean.flavorsList}" var="cur" varStatus="curStatus">
<ui:repeat value="#{repeatBean.flavorsList}" var="cur1" varStatus="curStatus1">
<h:commandLink id="link" action="#{bean1729.doIt}" value="Tja" >
<f:ajax render="out"/>
</h:commandLink>

<p><h:outputText id="out" value="actionListenerMessage: #{flash['processActionListenerMessage']}"/></p>
</ui:repeat>
</ui:repeat>

The commandLink request is fired over ajax, and the action is performed.
The action puts a value into Flash, and the "render" target of f:ajax displays it.

Perhaps you can provide your example (with source) if it is small enough.
Try with the latest build of GF v3.


adriaaaaan added a comment - 14/Feb/11 02:08 AM

But does the given example work?

I'll try and get a close as possible testcase from our software, it wont be easy as its complex (a richdatatable done entirely in a composite component).
In glassfish v3 it works in 3.1 it doesn't and its the same if you copy the version of jsf from 3.1 and put it in v3.

The basic jist of it is this: (i've removed the dynamic column headers, the delete button here never calls the method in the managed bean on jsf 2.1 but does in 2.0.2)

I'll get a test case asap

<h:panelGroup id="contenttable" layout="block">
<table>
<tbody>
<ui:repeat value="#{cc.attrs.databean.dataModel}" var="row">
<tr>
<td>
<h:commandButton value="Delete"
rendered="#{cc.attrs.databean.deleteButton}"
type="button"
image="resources/images/icons/smallest/delete.png"
action="#{cc.attrs.databean.redSelection(row.transientKey)}">
<f:ajax/>
</h:commandButton>
</td>
<ui:repeat value="#{cc.attrs.databean.columns}" var="column">
#{column.setRow(row)}
<td style="#{column.definition.visible?'':'display:none'}" class="#{column.headerClass}">
<h:outputLink target="_blank" title="#{column.toolTip}" value="#{column.link}" rendered="#{column.hasHyperlink()}" styleClass="text bold">
<h:outputText value="#{applicationUtils.textField(column.value, column.wrapText, column.nullValueName)}" escape="false"/>
</h:outputLink>
<h:outputText value="#{applicationUtils.getTextField(column.value, column.wrapText, column.nullValueName)}" rendered="#{!column.hasHyperlink()}" escape="false"/>
</td>
</ui:repeat>
</tr>
</ui:repeat>
</tbody>
</table>
</h:panelGroup>


adriaaaaan added a comment - 14/Feb/11 03:32 AM

I can't replicate it either using a similar example above, It was certainly broken before (i had a test case ages ago) so this issue appears to be fixed. My program however still suffers from the same symptoms. On further investigation I have found that re-enabling partial state saving fixes my table. It is currently disabled at the moment as a workaround for issues around c:foreach which a previous version of our data table uses. In other words theres a regression in partial state saving somewhere but more importantly it means i can fix my program by upgrading the rest of the ui to not use any of the nastly jstl stuff.


rogerk added a comment - 14/Feb/11 06:26 AM

Fixed per reporter comments.


Mathias Werlitz added a comment - 15/Feb/11 01:14 AM

I CANNOT confirm that this bug is fixed with 2.1.0-b11 that is included with the latest glassfish 3.1.


adriaaaaan added a comment - 16/Feb/11 02:21 AM

Its possible i may have made a configuration error and mixed up my jsf versions but it definitely isnt working (sorry). I'll make a quick binary version to prove this.


adriaaaaan added a comment - 16/Feb/11 03:12 AM

I have a test app that works in gf v3 and fails on gf3.1 but i am unable to attach it


adriaaaaan added a comment - 16/Feb/11 06:46 AM

To further elaborate, the ajax part does function, in that post occurs, and update is returned and the components in render are redrawn. The problem is is that since the action is never called, the state never alters and so the button has no effect. The bug must exist somewhere in linking the post to the action. Heres what the same button in the same application posts to glassfish (take through firebug), it works in v3 but not in 3.1

v3.1
features=features
&features:featureDialog:scraperJobId=
&features:featureDialog:domain=
&features:featureDialog:benice=
&features:featureDialog:type=CACHED
&features:featureDialog:testUrl=
&features:featureDialog:featureDefinitions:reportTaskId=0
&features:featureTable:rowsPerPage=20
&features:featureTable:searchBox=
&features:featureTable:reportTaskId=0
&javax.faces.ViewState=-889545474866681378:8881515505272268546
&javax.faces.source=features:featureTable:repeatLevel_1:0:repeatLevel_2:0:repeatLevel_3:0:button
&javax.faces.partial.event=click
&javax.faces.partial.execute=features:featureTable:repeatLevel_1:0:repeatLevel_2:0:repeatLevel_3:0:button
&javax.faces.partial.render=features:featureTable:repeatLevel_1:0:repeatLevel_2:0:repeatLevel_3:0:button%20features:featureTable:deleteAction
&javax.faces.behavior.event=action
&javax.faces.partial.ajax=true

v3
features=features
&features:featureDialog:scraperJobId=0
&features:featureDialog:domain=
&features:featureDialog:benice=10
&features:featureDialog:type=CACHED
&features:featureDialog:testUrl=
&features:featureDialog:featureDefinitions:reportTaskId=0
&features:featureTable:rowsPerPage=20
&features:featureTable:searchBox=
&features:featureTable:reportTaskId=0
&javax.faces.ViewState=7703656774392090610:-8944148323286296112
&javax.faces.source=features:featureTable:repeatLevel_1:0:repeatLevel_2:0:repeatLevel_3:0:button
&javax.faces.partial.event=click
&javax.faces.partial.execute=features:featureTable:repeatLevel_1:0:repeatLevel_2:0:repeatLevel_3:0:button
&javax.faces.partial.render=features:featureTable:repeatLevel_1:0:repeatLevel_2:0:repeatLevel_3:0:button%20features:featureTable:deleteAction
&javax.faces.behavior.event=action
&javax.faces.partial.ajax=true

Its interesting (but possibly not relevant?) that theres no default values for scraperJobId and beNice in 3.1.


adriaaaaan added a comment - 16/Feb/11 06:47 AM

This is a triple nested repeat, the same button appears to work in the double nested layer.


adriaaaaan added a comment - 16/Feb/11 10:08 AM

I've spent half the day trying to get the jsf 2.1 source but the page doesnt work http://java.net/projects/svn/svn/mojarra~svn/. Could you tell me where to get the source + netbeans project from svn? Having debugged it and compared the identical working button with the broken one it seems to not find the button during visitTree and hence never calls decode and then never populates the list of events to action. Since this part of ui:repeat has changed since 2.0.2 (where it works) i was thinking of building my own 2.1 with 2.0.2's ui:repeat and see if that fixes it.


rogerk added a comment - 16/Feb/11 10:44 AM

adriaaaaan added a comment - 17/Feb/11 02:12 AM

That just returns 404?


adriaaaaan added a comment - 17/Feb/11 02:22 AM

Ah okay it works fine through svn, but the browser giving 404 is rather confusing :S


adriaaaaan added a comment - 17/Feb/11 04:07 AM

Could you reopen this? Then i'll attach the test case.


rogerk added a comment - 17/Feb/11 04:51 AM

reopening per reporter's request.


rogerk added a comment - 17/Feb/11 04:53 AM

I've reopened the issue. Please attach a simple example that illustrates the problem. This will also enable us to use it in our test harness to help minimize regressions in the future. When I say "simple" example, I mean it would be ideal if this example did not rely on any third party libs or frameworks such as RichFaces.


adriaaaaan added a comment - 17/Feb/11 07:26 AM

The following attachment shows the bug,
To reproduce:
press on the red cross button, though the row highlights red (client side js) and a post is made to glassfish the button never calls the selection action. Therefore if you press refresh the row is unselected. Also the button at the top called (Delete marked rows) is never enabled and therefore rows can never be deleted.

On glassfish 3.0.1 (mojarra 2.0.2) it should work as expected and you can delete rows.


rogerk added a comment - 17/Feb/11 07:37 AM

You have a lot of stuff in the sample application you attached.
So, presumably, you are saying that when f:ajax is nested within three ui:repeat tags it does not work:

<ui:repeat>
<ui:repeat>
<ui:repeat>
...
<f:ajax..../>

If so, can you please strip this down to a simple example illustrating the problem?

Thanks


adriaaaaan added a comment - 17/Feb/11 07:48 AM

Yes, thats pretty much it. I've stripped this as much as possible without rewriting it. If you try your example with three nests it should stop working also


adriaaaaan added a comment - 17/Feb/11 08:59 AM

I think i may have figured it out, or at least have a strong suspect...

A Simple example like this :
<ui:repeat value="#{testbean.dataModel}" var="item1">
<ui:repeat value="#{testbean.dataModel}" var="item2">
<ui:repeat value="#{testbean.dataModel}" var="item3">
<h:commandButton value="test3" type="button" action="#{testbean.action()}">
<f:ajax render=":form:text"/>
</h:commandButton>
</ui:repeat>
</ui:repeat>
</ui:repeat>

works but this.... (where I use an object from the var attribute)

<ui:repeat value="#{testbean.rows}" var="item1">
<ui:repeat value="#{testbean.columns}" var="item2">
<ui:repeat value="#{item2.buttons}" var="item3">
<h:commandButton value="test3" type="button" action="#{testbean.action()}">
<f:ajax render=":form:text"/>
</h:commandButton>
</ui:repeat>
</ui:repeat>
</ui:repeat>

DOES NOT!

I'll make an example that can demonstrate this


adriaaaaan added a comment - 17/Feb/11 09:14 AM

Attached a new example, shows a double nested repeat where the second repeat uses a collection from an item given by the first repeat.
e.g

<ui:repeat id="r1" value="#{testbean.columns}" var="item2">
<ui:repeat id="r2" value="#{item2.buttons}" var="item3">

it seems that because "r2" uses a collection given from an item from "r1" ActionEvents are not created when submitting ajax events


Mathias Werlitz added a comment - 17/Feb/11 11:45 PM

Yes, thats exactly what my original example is about.


knob_creek added a comment - 02/Mar/11 10:27 AM - edited

The latter examples seem to hit the point. I have another example with only a single ui:repeat loop, which might have the same cause. This is deployed in an ear into JBoss 5.1 having Mojarra 2.0.4 copied in.

The links below work on every other click only, i. e. the first click works, the 2nd one is ignored a. s. o.:

<h:form id="menu">
<ul id="menu">
<ui:repeat var="item" value="#{seitenAuswahl.menu}">
<li id="#{item.id}" class="#{item.style}">
<h:commandLink value="#{item.value}"
actionListener="#{item.doAction}" action="#{item.action}">
<f:ajax render="@form"/>
</h:commandLink>
</li>
</ui:repeat>
</ul>
<h:messages showDetail="true"/>
</h:form>

I need the item to process the action event (instead of the managed bean) since the id of the commandLink cannot be an EL-expression. (At least i get an IllegalArgumentException "Empty id attribute is not allowed" if i try to.)

Leaving out the f:ajax tag (which is not strictly necessary) renders the commandLinks unresponsive and leads to JavaScript errors.

Edit: The problem is still present in Mojarra 2.1.0. Are you interested in a small example (1 facelet, 2 classes)?


Mathias Werlitz added a comment - 10/Mar/11 08:42 AM

Uploaded a tiny example (2 classes and one page)


adriaaaaan added a comment - 18/Mar/11 04:33 AM

werlitz, if it helps I've found that richfaces 4's equivlent to ui:repeat (a4j:repeat) actually works! Its only an initial test but My complex datatable component now works if i replace every occurance of ui:repeat with a4j:repeat. Might be worth considering since you're stuck in the same rut as I.


Mathias Werlitz added a comment - 21/Mar/11 05:07 AM - edited

MyFaces 2.0.4 might be also worth considering, it doesn't suffer from this issue.


Marcel Kolsteren added a comment - 26/Mar/11 01:34 PM

I have the same issue in my JSF 2.0 application, running on Mojorra 2.1.0, with a ui:repeat nested within a h:dataTable.

I found a workaround: add an execute attribute to the f:ajax, wide enough to ensure that the h:dataTable is included in the execution. That workaround also works for the example "1817.zip" (with execute="@form" added to the failing f:ajax element).


sinixtek added a comment - 18/Jan/12 12:15 PM

Still happens with Mojarra 2.1.6. Cannot make execute target wider, as, in my case, ajax is internally generated by the component suite.


n.lundquist added a comment - 11/Oct/12 05:59 PM

Hi, I'm a developer with ICEsoft Technologies who has encountered this issue as well, specifically in the case of nesting a ui:repeat inside an h:dataTable, where the repeat values are a property of the table values.

I'm attaching a simplified Maven-based test case that builds for servlet containers by default.

I've also investigated the issue in some detail and found the root of the issue. The problem is that the Mojarra implementation of UIRepeat, during a narrow partial execute on one of its descendants, caches an empty data model. The model is cached by the component during the restoreView phase, which is not an iterative visiting. This means that the parent iterative container doesn't expose values to the repeat, so the repeat creates and caches an empty model.

The component code acknowledges that an empty model may be cached from an non-iterative phase and in processDecodes and encodeEnd calls setDataModel(null) to clear the cached model and generate a new one. However because this partial execute is narrowed to a descendant of the repeat, processDecodes is never called on the repeat (rather it is run on the executing descendant component), and the incorrect empty model is held until rendering. The model regeneration in processDecodes explains why the issue is fixed by expanding the scope of the execution.

I propose that the model not be cached during non-iterative visits, or that the model be cleared in visitTree as it is in processDecodes.


rogerk added a comment - 26/Oct/12 06:51 PM

Thanks for the detailed analysis. I verified that clearing the datamodel in visitTree appears to work. I'll need to run this through all our tests to make sure it does not break something else.


rogerk added a comment - 30/Oct/12 01:38 PM

Changes.


rogerk added a comment - 30/Oct/12 01:41 PM

Committed to MOJARRA_2_1X_ROLLING:
Sending jsf-ri/src/main/java/com/sun/faces/facelets/component/UIRepeat.java
Adding test/agnostic/ajax/src/main/java/com/sun/faces/test/agnostic/ajax/Issue1817Bean.java
Adding test/agnostic/ajax/src/main/java/com/sun/faces/test/agnostic/ajax/Issue1817Item.java
Adding test/agnostic/ajax/src/main/webapp/issue1817.xhtml
Adding test/agnostic/ajax/src/test/java/com/sun/faces/test/agnostic/ajax/Issue1817IT.java
Transmitting file data .....
Committed revision 10936.


rogerk added a comment - 30/Oct/12 01:53 PM

Committed to trunk:
Sending jsf-ri/src/main/java/com/sun/faces/facelets/component/UIRepeat.java
Adding test/agnostic/ajax/src/main/java/com/sun/faces/test/agnostic/ajax/Issue1817Bean.java
Adding test/agnostic/ajax/src/main/java/com/sun/faces/test/agnostic/ajax/Issue1817Item.java
Adding test/agnostic/ajax/src/main/webapp/issue1817.xhtml
Adding test/agnostic/ajax/src/test/java/com/sun/faces/test/agnostic/ajax/Issue1817IT.java
Transmitting file data .....
Committed revision 10937.


rogerk added a comment - 30/Oct/12 01:54 PM

Committed.