Details
-
Type: Bug
-
Status: Closed
-
Priority: Major
-
Resolution: Invalid
-
Affects Version/s: 1.7DR#2
-
Fix Version/s: None
-
Component/s: ICE-Components
-
Labels:None
-
Environment:Unknown
-
ICEsoft Forum Reference:
-
Workaround Exists:Yes
-
Workaround Description:HideBind the component and programmatically set the value on the component (each time the contents of the component changes):
dataTable.setValue(list);ShowBind the component and programmatically set the value on the component (each time the contents of the component changes): dataTable.setValue(list);
Description
This may affects ice:dataTable as well.
-
Hide
- Test_RowSelectorPanelSeries.war
- 5.63 MB
- Philip Breau
-
- META-INF/MANIFEST.MF 0.0 kB
- WEB-INF/classes/com/.../common/Person.class 2 kB
- WEB-INF/.../DataTablePaginatorBean$1.class 2 kB
- WEB-INF/.../DataTablePaginatorBean.class 4 kB
- WEB-INF/classes/.../table/SortableList.class 1 kB
- WEB-INF/classes/.../table/TableBean.class 4 kB
- WEB-INF/classes/.../messages.properties 22 kB
- WEB-INF/faces-config.xml 0.5 kB
- WEB-INF/html_basic.tld 244 kB
- WEB-INF/jsf_core.tld 25 kB
- WEB-INF/lib/backport-util-concurrent.jar 343 kB
- WEB-INF/lib/commons-beanutils.jar 116 kB
- WEB-INF/lib/commons-collections.jar 167 kB
- WEB-INF/lib/commons-digester.jar 140 kB
- WEB-INF/lib/commons-fileupload.jar 52 kB
- WEB-INF/lib/commons-logging.jar 31 kB
- WEB-INF/lib/el-api.jar 24 kB
- WEB-INF/lib/el-ri.jar 97 kB
- WEB-INF/lib/icefaces-comps.jar 1.48 MB
- WEB-INF/lib/icefaces.jar 744 kB
- WEB-INF/lib/jsf-api.jar 356 kB
- WEB-INF/lib/jsf-impl.jar 679 kB
- WEB-INF/lib/jstl.jar 20 kB
- WEB-INF/.../krysalis-jCharts-1.0.0-alpha-1.jar 151 kB
- WEB-INF/lib/standard.jar 384 kB
- WEB-INF/lib/xercesImpl.jar 1.15 MB
- WEB-INF/lib/xml-apis.jar 190 kB
- WEB-INF/web.xml 3 kB
- index.jspx 0.8 kB
- panelSeries.jspx 5 kB
Activity
- All
- Comments
- History
- Activity
- Remote Attachments
- Subversion
I am getting the same caching issue for a single column datatable too....Here is how this can be reproduced.
1.Create a page with a dropdown values 1..n and a datatable with dateinput control.(default is cobobox selected one and date input with today's date)
2. wire it up so that when you select 2 in the combobox the datatable should show 2 dateInput controls(with default date as today's date)...so on...it should also reduce the number of rows int he datatable when the selected number in the combobox is decreased.
3. select 2 in the drop down and in the new dateinput row select yesterday's date, leave the row 1 as is, which is today's date.
4. select 1 in the drop down, now the datatable should have only the first row.
5. select 2 in the combo box again, instead of showing the selecond row with todays date it shows the old value, which is yesterday's date.
GenerateMethodAccessor.invoke() seems to be calling the setter method on the date attribute of the bean that maps to each row of the datatable with the old date and that is why it is showing the old value
test case
/Test_RowSelectorPanelSeries/panelSeries.iface shows normally functioning panelSeries.
/Test_RowSelectorPanelSeries/panelSeriesInTabSet.iface shows a panelSeries nested in a UISeries component (TabSet) and shows that the first set value of the panelSeries is cached.
This involves a panelSeries nested in any UISeries component (dataTable, panelSeries, panelTabSet, etc). If the change in the panelSeries list value is being driven by a JSF event (such as a row selection event) you can get around the caching by requeuing the event for the Invoke Application phase (recent work on the row selector event code breaks this workaround ) or accessing and clearing the savedChildren property of UISeries is another workaround.
That sounds like the bug could be present whether or not ICEfaces is used; is that the case?
Using ui:repeat the problem is removed.
Anto!
In regards to the row selection not updating the list on the far right, what's happening is that the inputText components on the far right are rendering the first data. Then the user clicks to select a different row, and that causes a form submission. The old values from the old row become the new submittedValues of the inputText components. The rowSelector 's decode queues its selectionListener event and then calls renderResponse(), which means that the application is informed of the new row selection, but that validation and the UPDATE MODEL (and INVOKE APPLICATION) phases don't happen. So, the submittedValues don't get set into the beans, and just remain as submittedValues. When the RENDER phase comes, the inputTexts prioritise rendering the submittedValues, which is the old row data, instead of their values, which would have evaluated to the new row data.
A simple work-around is to nuke the submittedValues in the selectionListener. Eg:
public void selectionListener(RowSelectorEvent e)
{ recurseClearUIInput(FacesContext.getCurrentInstance().getViewRoot()); }private void recurseClearUIInput(UIComponent comp)
{ if(comp instanceof UIInput) ((UIInput)input).resetValue(); java.util.Iterator kids = comp.getFacetsAndChildren(); while(kids.hasNext()) recurseClearUIInput((UIComponent)kids.next()); }Here's a test case for Anil's comment on December 11, 2007:
public static class RowElem {
private static int uniqueCounter = 0;
private Date date = new Date();
public Date getDate()
public void setDate(Date d)
{ date = d; } private int unique = uniqueCounter++;
public int getUnique()
public void setUnique(int u)
{ unique = u; }}
private String count = "1";
public String getCount()
public void setCount(String c)
{ count = c; } private List rows;
public List getRows()
public void setRows(List r)
{ rows = r; } public void valueChangeListener(ValueChangeEvent event) {
Object newValue = event.getNewValue();
int newCount = Integer.parseInt(String.valueOf(newValue));
int oldSize = rows.size();
if(newCount > oldSize)
else if(newCount < oldSize)
{ for(int i = oldSize-1; i >= newCount; i--) rows.remove(i); }}
public TextFieldsBean()
{ rowList = new ArrayList(); for(int i = 0; i < 10; i++) rowList.add( new RowEntry(i) ); rows = new ArrayList(); rows.add( new RowElem() ); }<ice:panelGroup style="width:300px;height:300px">
<ice:selectOneMenu value="#
"
partialSubmit="true"
valueChangeListener="#
">
<f:selectItem itemValue="1"/>
<f:selectItem itemValue="2"/>
<f:selectItem itemValue="3"/>
<f:selectItem itemValue="4"/>
<f:selectItem itemValue="5"/>
</ice:selectOneMenu>
<ice:dataTable var="rowElem" value="#
">
<ice:column>
<f:facet name="header">
<ice:outputText value="Date"/>
</f:facet>
<ice:selectInputDate value="#
" renderAsPopup="true"/>
</ice:column>
<ice:column>
<f:facet name="header">
<ice:outputText value="Unique"/>
</f:facet>
<ice:outputText value="#
"/>
</ice:column>
</ice:dataTable>
</ice:panelGroup>
The "unique" field shows that I am getting a new RowElem object, it's just that it's having its date field reset to the old one's value.
I made a stock JSF app that also demonstrates this problem, so it's not ICEfaces specific.
Basically, there are two parts of this issue. The first is that UIData stores the EditableValueHolder state by clientId, which means that when your data objects change in your data model, either in-place, or by adding or removing entries, there's no simple means of clearing that specific state, from the data model's perspective. Secondly, top level UIData behave differently than nested UIData, since nested UIData specifically hold onto their EditableValueHolder state longer.
Add this snippet to the Bean class:
public List getOuter()
{ List outer = new ArrayList(1); outer.add("Outer"); return outer; }And use this for your .xhtml/.jspx file:
<h:form id="iceform"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component">
<!-- Uncomment this to "break" the app
<h:dataTable value="#
">
<h:column>
-->
<h:panelGroup style="width:300px;height:300px">
<h:selectOneMenu value="#
"
valueChangeListener="#
">
<f:selectItem itemValue="1" itemLabel="1"/>
<f:selectItem itemValue="2" itemLabel="2"/>
<f:selectItem itemValue="3" itemLabel="3"/>
<f:selectItem itemValue="4" itemLabel="4"/>
<f:selectItem itemValue="5" itemLabel="5"/>
</h:selectOneMenu>
<h:dataTable var="rowElem" value="#
">
<h:column>
<f:facet name="header">
<h:outputText value="Date"/>
</f:facet>
<h:inputText value="#
">
<f:convertDateTime/>
</h:inputText>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Unique"/>
</f:facet>
<h:outputText value="#
"/>
</h:column>
</h:dataTable>
<h:commandButton value="Submit"/>
</h:panelGroup>
<!-- Uncomment this to "break" the app
</h:column>
</h:dataTable>
-->
</h:form>
So there's the work-around of re-queuing the event for INVOKE APPLICATION (or even UPDATE MODEL), for now, but no bug, per se, to fix. After the 1.7 Beta release we'll investigate an enhancement to help developers side-step this issue.
Oh yes, and we changed rowSelector back, so it doesn't call FacesContext.renderResponse() itself, so requeuing should work there too. Of course, if you need renderResponse() called, you can do that yourself in your selectionListener.
This issue might have been affected by changes for ICE-3306.
Let's doc why this doesn't need to be fixed and close it.
This is not a bug, as explained by my comment on [05/Feb/08 08:59 PM].
...six months later Mark, could you please describe the work-around with re-queuing INVOKE APPLICATION/UPDATE MODEL. Where (lifecycleListener?) and how to do it right? And what about the "enhancement to help developers side-step this issue"?
Ok, let's say you have a rowSelector and input components, and need the rowSelector's selectionListener to be called in INVOKE_APPLICATION, so that the input components' submittedValues will be pushed into the bean, in UPDATE_MODEL, before the selectionListener is called.
The original solution was to do:
public void selectionListener(RowSelectorEvent event) {
if(!event.getPhaseId().equals(javax.faces.event.PhaseId.INVOKE_APPLICATION))
// Now do your processing
}
Then we added a feature to rowSelector, where you could set immediate="false" on it, and the selectionListener would be called in INVOKE_APPLICATION for you, without the re-queue code.
But, for other components, like input components and their valueChangeListener, there was no easy way of having them be called in INVOKE_APPLICATION. In ICEfaces 1.8 RC1 we introduced the ice:setEventPhase component, which is the general solution for changing what phase events will be broadcast in, and so the phase the listeners will be invoked in. You can still use immediate, but setEventPhase makes it unnecessary.
Actually I had the problem with BooleanCheckboxes in the <ice:dataTable>. If the underlying model changed (values were get and set properly), and the number of checkboxes stayed the same the view didn't reflect the model. I hacked it temporary by adding the valueChangeListener like:
public void valueChangeListener(ValueChangeEvent event){
if(!event.getPhaseId().equals(javax.faces.event.PhaseId.INVOKE_APPLICATION))
HtmlSelectBooleanCheckbox checkbox = (HtmlSelectBooleanCheckbox) event.getSource();
checkbox.setId("checkbox" + checkboxId++); //change of id forces icefaces to redraw the component
}
Is there any other (proper) way to force the icefaces to redraw the component? I know that ASP.NET controls have Render() method.
The components are already redrawing themselves. As this Jira explains, the problem is that the UIData containers are storing the old values for the components. You have to call getSavedChildren().clear() on the UIData/UISeries parents if you update your model values.
To Wladyslaw Bultrowicz, immediate="false" on row selector didn't resolved your problem?
In our master-detail view it helps.
I have also run into the same issue, the I have 2 panelseries nested to show a set of images in a 2 dimensional matrix(when a set of checkboxes are clicked), If i use a single panel series it works but all the images shows up in a single row. Using the nested panelseries with nested beans solves the problem half way first time all the images gets rendered, but when the checkbox is clicked. When i uncheck the checkbox the image disappears if the full row is unchecked but, when i check it again it somehow remebers the whole row.