Issue Details (XML | Word | Printable)

Key: JAVASERVERFACES-2490
Type: Bug Bug
Status: Closed Closed
Resolution: Works as designed
Priority: Major Major
Assignee: Manfred Riem
Reporter: jasonzhang2002gmailcom
Votes: 0
Watchers: 0
Operations

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

UIData does not keep submitted value when there is no error with a immediate button

Created: 05/Aug/12 09:29 AM   Updated: 17/Sep/13 08:58 PM   Resolved: 17/Sep/13 08:58 PM
Component/s: ajax
Affects Version/s: 2.1.19
Fix Version/s: None

Time Tracking:
Not Specified

File Attachments: 1. File jsf2490.tgz (4 kB) 07/Dec/12 12:29 AM - jasonzhang2002gmailcom

Environment:

glassfish 3.1.2

Issue Links:
Related
 

Tags:
Participants: jasonzhang2002gmailcom and Manfred Riem


 Description  « Hide

I have dataTable which contains inputText child. Outside of the datatable, there is an ajax button which add more value to datatable model data and refresh the datatable. Basically, I use ajax to add new row to datatable. The immediate is set to true for ajax since I do not want to validate the entered data in datatable at this time. However, I do not want to lose any data already entered by the user. So the whole datatable is sent to server for execution. Since the button is set to immediate, the data inside datatable will not be validated and should be sent back to browser. But empty text is sent back, and entered data are lost.

Test case:

<h:form>
		<h:dataTable  value="#{test.values}" var="item" id="tables">
			<h:column>
				<h:inputText value="#{item.value}"></h:inputText>
			</h:column>
		</h:dataTable>
		<h:commandButton id="adder" value="Add" actionListener="#{test.action}" immediate="true">
			<f:ajax	render="tables" execute="@form" listener="#{test.addOneValue}" immediate="true"></f:ajax>
		</h:commandButton>
	</h:form>

Code

@Named("test")
@SessionScoped
public class Test1 implements Serializable
{

	
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	List<ValueHolder<String>> values=new LinkedList<ValueHolder<String>>();

	public List<ValueHolder<String>> getValues()
	{
		return values;
	}

	public void setValues(List<ValueHolder<String>> values)
	{
		this.values = values;
	}
	
	public void addOneValue(javax.faces.event.AjaxBehaviorEvent event) throws javax.faces.event.AbortProcessingException
	{
		values.add(new ValueHolder<String>());
	}
	
	public void action()
	{
		System.out.println("called");
	}
	
	
	
}

I trace the code to keepSaved method in UIData class

line 2176: private boolean keepSaved(FacesContext context) {

        return (contextHasErrorMessages(context) || isNestedWithinUIData());

    }

To prove this,
if I intentionally add a useless FacesMesage
Modified Code

public void addOneValue(javax.faces.event.AjaxBehaviorEvent event) throws javax.faces.event.AbortProcessingException
	{
		values.add(new ValueHolder<String>());
		FacesMessage msg=new FacesMessage("new item is added");
		FacesContext.getCurrentInstance().addMessage(null, msg);
	}

This will make keepSaved return true. Entered data in datatable are sent back to browser.

This issue is very similar to issue 73 which is closed. But I guess it is not fixed completely.



Manfred Riem added a comment - 31/Oct/12 02:05 PM

Can you reproduce the problem on the most recent 2.1 release?


jasonzhang2002gmailcom added a comment - 07/Dec/12 12:29 AM

The attached file is simple eclipse project to reproduce the problem. This problem also occurs in jsf 2.1_14, the latest release

deploy it to glassfish, go to index.xhtml, change any text field, click "Add Row" button, the changed text is lost. Change any text again, click "Add Row With Message", the change is kept. The only difference between this two ajaxes is a useless FacesMessage in server.

This should be an major issue instead of a minor one. UIData uses existence of FacesMessage to decide whether to send the submitted table back to user or not. This is a hack, isn't it?

-jason


Manfred Riem added a comment - 18/Feb/13 02:31 PM

You mean 2.1.14 right?


jasonzhang2002gmailcom added a comment - 19/Feb/13 03:41 AM

I just tested with 2.1.19/2.2 milestone 09 and still see the problem in both releases


jasonzhang2002gmailcom added a comment - 11/Jul/13 02:50 AM

I tested this issue in 2.2.0 release. The issue still exists.
I finally tracked down the issue. I detailed the problem here :http://blog.flexdms.com/2013/07/immediate-action-for-data-under-uidata.html.
The issue boils down to this: In a ajax call, input data for component inside of UIData have gone through validation/update model phase. Otherwise, the submitted value are lost. This differs from how input component works outside of UIData.

My understanding is this: To find out whether there is validation error, UIData(DataTable and UIRepeat) only checks the existence of error message in FacesContext. This is good enough in practice. But it is definitely not a ideal solution.

This bug is not a big issue. Adding validation in my case is not ideal, but is not a big sacrifice. I guess you can change the priority to minor.

-jason


Manfred Riem added a comment - 17/Sep/13 08:58 PM

Unfortunately you have hit on something that would require a specification change. See http://docs.oracle.com/javaee/6/api/javax/faces/component/UIData.html#encodeBegin(javax.faces.context.FacesContext)

It states that per-row state of child components needs to be discarded, UNLESS it is needed to rerender the current page with errors. Your work-around basically triggers the UNLESS section.

Please file a spec issue if you think this should be addressed in a future revision of the specification. Thanks!