Details
-
Type: Bug
-
Status: Closed
-
Priority: Major
-
Resolution: Fixed
-
Affects Version/s: 3.2
-
Fix Version/s: 4.0
-
Component/s: ACE-Components
-
Labels:None
-
Environment:*
-
Assignee Priority:P1
Description
textAreaEntry
> Overview / Label Position / Indicator Text (After a validation message is generated on the page by clearing text from the required field, changing the label position from the drop-down renders the old input text from the required field at the same time with the validation error message - is this an issue?).
-
- screenshot-01.png
- 51 kB
-
- screenshot-02.png
- 199 kB
-
- screenshot-03.png
- 249 kB
-
- screenshot-04.png
- 222 kB
Issue Links
- depends on
-
ICE-9279 Propagate submittedValues between lifecycles
- Closed
Activity
- All
- Comments
- History
- Activity
- Remote Attachments
- Subversion
Re-render value determined by org.icefaces.ace.util.ComponentUtils#getStringValueToRender (PrimeFaces util?). Seems in the code it does make an attempt to look for submitted value, but somehow submitted value is not chosen.
The code looks correct, can you determine if submittedValue is somehow getting cleared, and if so why?
– Mark
See screenshot-01.png.
Tried immediate="true", as suggested by Mark. No difference.
Replaced <ace:textAreaEntry> with <h:inputTextarea>. Same result. See screenshot-02.png. Therefore, inherent JSF behavior?
I noticed similar behaviour in the singleSubmit tutorial, if one fills in the fields and then attempts to clear all the fields, then the previously cleared field will revert to re-filled.
There seems to be some history with singleSubmit and values reverting to older inputs in this case http://jira.icesoft.org/browse/ICE-8403. However, it was closed as not being reproducible. I've pared down the test to this JSF-only f:ajax powered form and removed icefaces.jar:
<h:form id="frm"> <f:ajax event="blur"> <h:panelGrid columns="3"> <h:outputLabel for="name" value="Name:"/> <h:inputText id="name" value="#{personBean.name}" required="true" maxlength="50"/> <h:message id="nameMsg" for="name"/> <h:outputLabel for="age" value="Age:"/> <h:inputText id="age" value="#{personBean.age}" required="true" size="2" maxlength="2"> <f:validateLongRange minimum="1" maximum="99"/> </h:inputText> <h:message id="ageMsg" for="age"/> </h:panelGrid> <h:commandButton id="submitId" value="Submit" actionListener="#{personBean.submitButton}"/> </f:ajax> </h:form>
And compared the behaviour to an ICEfaces-powered singleSubmit form:
<h:form id="frm"> <icecore:singleSubmit/> <h:panelGrid columns="3"> <h:outputLabel for="name" value="Name:"/> <h:inputText id="name" value="#{personBean.name}" required="true" maxlength="50"/> <h:message id="nameMsg" for="name"/> <h:outputLabel for="age" value="Age:"/> <h:inputText id="age" value="#{personBean.age}" required="true" size="2" maxlength="2"> <f:validateLongRange minimum="1" maximum="99"/> </h:inputText> <h:message id="ageMsg" for="age"/> </h:panelGrid> <h:commandButton id="submitId" value="Submit" actionListener="#{personBean.submitButton}"/> </h:form>
So far the behaviour between the two is not entirely consistent:
The ICEfaces version with the singleSubmit form shows the behaviour we are concerned about where it puts back in the old value when I clear out a field and trigger validation. The JSF-only version doesn't have the problem. It submits on blur but it's not triggering the validation when blurring; only when clicking the Submit button.
My guess is that when the field is cleared, the validation failure prevents the cleared field value from being set resulting in the next response returning the field to it's previous value. In other words:
- First, frm.name=Deryk is submitted
- then, frm.age=29 is submitted
- then, frm.age=0 is submitted but detected as invalid so 0 is not set
- then, frm.name=Elvis is submitted and the resulting response sets frm.age to 29
I presume that this problem is relatively unique to ICEfaces + singleSubmit + validation.
So i tweaked the f:ajax test a bit and added in MyFaces. I tested a matrix of:
- ICEfaces using <icecore:singleSubmit/>
- stock JSF using <f:ajax event="blur" execute="@this" render="@form"> (using render="@all" causes ViewRoot updates which have a different effect)
against
- Mojarra
- MyFaces
The result is that the problem only occurs when using Mojarra. The inclusion of ICEfaces is irrelevant and the problem doesn't manifest on MyFaces in either scenario. So it looks to be a Mojarra specific bug/behaviour. There may be a couple of cases that are related:
https://java.net/jira/browse/JAVASERVERFACES-838
https://java.net/jira/browse/JAVASERVERFACES-2264
One thing I found that changes the behaviour is:
<context-param> <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name> <param-value>true</param-value> </context-param>
When I add that to the test case, it modifies what happens:
- First, frm.name=Deryk is submitted
- then, frm.age=29 is submitted
- then, frm.age=0 is submitted but detected as invalid so 0 is not set - at this point the previous value of 29 is immediately restored
- then, frm.name=Elvis is submitted and frm.age remains 29
From looking at the code, I believe that this section in UIInput.validate() is the secret sauce:
// If non-null, an instanceof String, and we're configured to treat // zero-length Strings as null: // call setSubmittedValue(null) if ((considerEmptyStringNull(context) && submittedValue instanceof String && ((String) submittedValue).length() == 0)) { setSubmittedValue(null); submittedValue = null; }
Because if this isn't executed, then later in the same method:
// If our value is valid, store the new value, erase the // "submitted" value, and emit a ValueChangeEvent if appropriate if (isValid()) { Object previous = getValue(); setValue(newValue); setSubmittedValue(null); if (compareValues(previous, newValue)) { queueEvent(new ValueChangeEvent(this, previous, newValue)); } }
So the bottom line looks to be, when validation fails, and empty strings are not treated as NULL values (i.e. the context parameter is false, which is the default) then setSubmittedValue(null) is never called, leaving the old value in the component.
Upon searching for references to INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL, I came across some blogs and JIRAs that help explain what is going on:
So setting that parameter can introduce a different set of issues. The blog also suggests a patch to the HtmlBasicRenderer.getCurrentValue() method from this:
if (component instanceof UIInput) { Object submittedValue = ((UIInput) component).getSubmittedValue(); if (submittedValue != null) { // value may not be a String... return submittedValue.toString(); } }
to this:
if (component instanceof UIInput && !((UIInput) component).isValid()) { Object submittedValue = ((UIInput) component).getSubmittedValue(); if (submittedValue != null) { // value may not be a String... return submittedValue.toString(); } else { return null; } }
It also references another JIRA that was opened (but I can't verify at the moment as the JSF site is down):
The blog also states that, if you are using PrimeFaces, this should be fixed via ComponentUtils#getValueToRender() method. Going back to Yip's original analysis, he noted that he figures that the code should be able to handle this.
However, this particular code block won't be hit for stock components (which is what I was testing against). The code should be exercised for our ACE components. I took a quick look at the latest version of ComponentUtils in the PrimeFaces source tree and found that it's been significantly changed and improved since we forked it - including the logic for fixing this problem that the blog refers to. Perhaps someone on the Component team could look at the improvements in ComponentUtils to see if they can be ported forward to our version to resolve this.
The JIRAs around this appear to remain open. Additionally, there is an open spec issue:
https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-939
Doesn't work, not even after making an exact copy of the whole latest Primefaces methods (v. 3.5). All the fixes work only when component does both execute and render. The problem in this case is when component is rendered (by some other component) without execute. The submitted value from the last execute is simply lost. See screenshot for Primefaces code and more detailed annotations.
Suggestion from Mark: try putting components in separate columns of a table.
Working. See screenshot for the test case.
[2013-05-16 4:28:05 PM] Mark Collette: ICE-9279 : Propagate submittedValues between lifecycles
http://jira.icesoft.org/browse/ICE-9279
The same issue is seen with ace:textEntry and ace:maskedEntry.
Committed fix to 4.0 trunk at revision 41497. This fix was applied to ace:textEntry, ace:textAreaEntry and ace:maskedEntry. This issue has already been seen in ace:autoCompleteEntry (ICE-9722). The fix consists in checking if the component is valid or not before determining what value to render. If it's valid, proceed normally. If it's invalid, render the submitted (invalid) value.
This change is causing several serious regression failures:
1. autoCompleteEntry/ comboBox/ selectMenu/ simpleSelectOneMenu:
> Indicator Text: this demo is not functional after trying to disable the "Required" indicator, or after changing the Indicator position.
Also, the "Documentation" drop-down is rendered below the component page name after interacting with this demo.
Unable also to leave this page afterwards, must open a new browser window to be able to navigate to other demos.
2. dataTable
> Find: demo is not functional; after entering a search string and clicking "Find Next", characters disappear from search query text entry, there are no search results.
Also, the "Documentation" drop-down is rendered below the component page name after interacting with this demo.
Unable also to leave this page afterwards, must open a new browser window to be able to navigate to other demos.
The submittedValue is getting lost by the drop-down execute?
– Mark