JSF: Unable to set null values in h:inputText within ui:repeat - jsf

Mojarra 2.1.6 / Glassfish 3.1.2
I have something like this
<ui:repeat var="item" value="#{bean.items}">
<h:inputText value="#{item.longProperty}"/>
</ui:repeat>
where Item is an object with a Long property
public class Item {
private Long longProperty; // + getters/setters
}
It works fine as long as I'm setting longProperty to something not-null / non-empty.
When I do that, the null input is ignored and the old value is restored.
Similar results for Dates.
It makes no difference if I eliminate the reference to the var/status from the ui:repeat. Even explicitly referencing #{bean.items[0].longProperty} fails the same way.
The same exact h:inputText works fine outside of a ui:repeat and null/empty values work just fine.
Additionally, inside a ui:repeat, empty strings work ok, if the property is a String rather than an object that requires conversion.
To make it even weirder: if I put a valueChangeEvent on the input, I do see that event.getNewValue() returns null when I expect it - yet my setter is called with the old value.
Any idea what's going on?

Turns out its a Mojarra / JSF implementation bug with ui:repeat
http://java.net/jira/browse/JAVASERVERFACES-1721

And duplicated now, here (by Roger Kitain):
http://java.net/jira/browse/JAVASERVERFACES-2717

Change <ui:repeat> to <a4j:repeat> .
<a4j:repeat var="item" value="#{bean.items}">
<h:inputText value="#{item.longProperty}"/>
</a4j:repeat>
More info: Richfaces a4j:repeat.
See more about the <ui:repeat> bug at Problem with ui:repeat and NULL values in JSF 2.x.

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?

JSF 2.2 - everything inside ui:repeat is evaluated, although rendered = "false"

I'm currently migrating a web application from JSF 1.2/Richfaces 3.3.3 to JSF 2.2 For data iteration, we used a4j:repeat from Richfaces. I now want to change the iterators to ui:repeat, because we want to throw out Richfaces.
However, I came across a very strange behaviour. Imagine a code snippet like this (simplified from the original):
<ui:repeat id="criterions" var="criterion" value="#{AdvancedSearchBean.criterionList}">
<h:panelGroup rendered="#{criterion.searchCriterion.displayType == 'PERSON'}">
<h:inputText value="#{criterion.searchString}"/>
</h:panelGroup>
</ui:repeat>
The part inside the panelGroup is evaluated, although the rendered condition definitely evaluates to false. If I change ui:repeat to a4j:repeat, it works fine, the part inside the panelGroup is NOT evaluated.
This is a real problem for our code, as the "criterion" variable can contain different objects (extending the same superclass). In this case, the criterion object does not contain a property with the name "searchString" (because it is not of type "PERSON") -> an error is thrown.
Can anyone explain this behaviour or has a solution?
I'm using the JSF version integrated in WildFly 8.0.0.final (Mojarra 2.2.5-jbossorg-3)
Thanks
Markus

JSF binding with setValueExpression read-only?

I try to create an InputField in the backing bean and add it to the view, but the databinding seems to work just read-only.
I create a UIInput in the Backing-Bean like this:
UIComponent textInput = new UIInput();
textInput.setId("operandInputText");
textInput.setValueExpression("value", ef.createValueExpression(elCtx, "#{row.operandValues[0]}", String.class));
textInput.setValueExpression("rendered", ef.createValueExpression(elCtx, "#{row.inputType == 'text'}", Boolean.class));
mInputPanelGroup.getChildren().add(textInput);
The panelGroup is inside a column of a dataTable and bound to the bean:
<p:column id="operandColumn">
<h:panelGroup id="inputPanelGroup" binding="#{locateEmployeeBean.inputPanelGroup}" >
<h:inputText id="testInput" value="#{row.operandValues[0]}" />
</h:panelGroup>
</p:column>
The <h:inputText/> inside the PanelGroup is just for testing and this is where I found out that the binding I did with setValueExpression(...) works at least read-only.
In the browser I now have 2 inputFields, first the 'testInput' and then 'operandInputText'.
When I enter a value in 'operandInputText' and submit, the value does not get saved, but when I enter a value in the 'testInput'-Field, it get's submitted and in addition the value gets displayed in BOTH inputFields.
The operandValues is a simpe object array:
private Object[] mOperandValues = new Object[2];
Could this have anything to do with the dataType I pass to setValueExpression(...)?
I tried Object, but that didn't change anything.
Any idea why this happens?
Thanks in advance!
I found the solution to my problem. Honestly it was an article by #BalusC Using Datatables: Populate datatable what took me on the right path.
Previously I added the components during PreRenderView-Phase, then I saw in your example that you populate the bound component ONCE in the getter (which is then obviously way earlier during RestoreView-Phase). That is how I've done it now and it works flawlessly, the Inputfields now work both ways (read+write).
Thanks alot for your work #BalusC!

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?

Why is a dynamic created JSF EL value expression not resolved?

I got a simple setup (and a big issue): a JSP page with en empty panel grid item container and a binding to a bean.
<h:panelGrid binding="#{ bean.container }" id="container" />
When the getter of the bean will be called, the container is filled with a random number of columns with a command link inside. So far so good. The container is filled up with the right number of elements, and with the use of an ActionListener on the links, I get all click events.
Here comes the tricky part: I want to mark the 'selected' or 'pressed' column via a different style class. With a static setup, I would do this with an expression like:
<h:column styleClass="#{ bean.selectedColumn eq 'id' ? 'btnSelected' : 'btn' }">
<!-- command link and some blahblah -->
</h:column>
The bean contains a simple getter getSelectedColumn() , that returns an id. Straight forward, so this works perfect!
But when I try to do the same inside the bean,
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
String expression = "#{ bean.selectedColumn eq 'id' ? 'btnSelected' : 'btn' }";
new ExpressionFactoryImpl().createValueExpression(elContext, expression, String.class);
column.setValueExpression("styleClass", valueExpression);
the expression won't ever be resolved. To make myself clear: both the command links, the columns and the value expressions are generated inside the bean. Is that the cause?
Can anyone tell me why? Thanks in advance!
When the JSP is compiled the bean wont be called! This is done at runtime cause you want to see live data in the bean. Therefore the (later) generated EL is not visible at compilation. The EL would not be resolved at runtime.

Resources