Problem with JSF remembering old values

I'm new to JSF, but I've been trying it out, and have problems with JSF remembering and restoring component values that I don't want it to.

I am writing a JSP page that allows users to edit contacts. So if a user wants to edit contact #1, he goes to the page "/edit.jsf?id=1", or id=2, and so on.

When a page request is made, the request scope backing bean's constructor loads the contact values it needs. This arrangement usually works fine.

That edit.jsf (actually edit.jsp) page has <h:inputText> tags for editing the contact information. Some of these are mandatory, so are set to required=true.

The problem begins innocently does something like blank a required inputText and submits it with the <h:commandButton> provided in the form. JSF detects that this is invalid, and redisplays edit.jsf with the submitted data, and an <h:message> error message. So far, so good.

But then, if the user decides that that particular contact, call that one #1, really didn't need to be edited anyway, and goes on to edit another contact, say #2, without correcting and resubmitting the form, then the page for contact #2 ("/edit.jsf?id=2") will populate the form with the information from the previously submitted contact #1.

It makes sense that JSF "remembers" the submitted values when redisplaying edit.jsf after the validation error, but isn't the JSF framework smart enough to figure out that it shouldn't do that for subsequent requests? Is there a way to get around this problem by somehow clearing something in FacesContext, or kicking the JSF page out of whatever lifecycle stage it's stuck in?

I agree with you that JSF framework was loading the previous values, contact #1, in restore view phase. But I think you are always allowed to fetch new values, contact #2, in apply request values phase.

I don't have the code with me right now, but basically, it's very simple. The JSP uses <h:inputText> elements with required set to true. When the problem occurs, the values from the backing bean are not used, of course, since the inputText values become "sticky", so the backing bean is out of the equation as a source of the problem.

Originally posted by Bagwan Mehrat: I'm new to JSF, but I've been trying it out, and have problems with JSF remembering and restoring component values that I don't want it to.

I am writing a JSP page that allows users to edit contacts. So if a user wants to edit contact #1, he goes to the page "/edit.jsf?id=1", or id=2, and so on.

When a page request is made, the request scope backing bean's constructor loads the contact values it needs. This arrangement usually works fine.

That edit.jsf (actually edit.jsp) page has <h:inputText> tags for editing the contact information. Some of these are mandatory, so are set to required=true.

The problem begins innocently does something like blank a required inputText and submits it with the <h:commandButton> provided in the form. JSF detects that this is invalid, and redisplays edit.jsf with the submitted data, and an <h:message> error message. So far, so good.

But then, if the user decides that that particular contact, call that one #1, really didn't need to be edited anyway, and goes on to edit another contact, say #2, without correcting and resubmitting the form, then the page for contact #2 ("/edit.jsf?id=2") will populate the form with the information from the previously submitted contact #1.

It makes sense that JSF "remembers" the submitted values when redisplaying edit.jsf after the validation error, but isn't the JSF framework smart enough to figure out that it shouldn't do that for subsequent requests? Is there a way to get around this problem by somehow clearing something in FacesContext, or kicking the JSF page out of whatever lifecycle stage it's stuck in?

I'm using JBoss 4.0.3, which bundles Tomcat and MyFaces.

I haven't faced this problem. Okay, is your javax.faces.STATE_SAVING_METHOD set to "server" or "client" in web.xml file? If it is "server" or not explicitly specified to "client", please try setting it to "client" and see if it works.

- Varun

Bagwan Mehrat
Ranch Hand

Joined: Jan 26, 2002
Posts: 119

posted Sep 09, 2005 14:50:00

0

To answer my own question, to work around this problem what I had to do was allow the user navigate back to the previous list page with a commandButton or commandLink. If the user navigates back using a plain outputLink or even using the browser Back button, JSF gets confused.

Bagwan Mehrat
Ranch Hand

Joined: Jan 26, 2002
Posts: 119

posted Feb 08, 2006 09:08:00

0

I know this post is a bit old, but I'm bringing up this issue again because my previous workaround is obviously not a real fix.

I think the fact that I haven't been able to find a solution to such a fundamental problem for such a long time reflects a deep problem with either the framework, or with my brain.

So after having let this stew for a while, does anyone still have any ideas about this issue? It's really annoying that parameters that you were programmed to be request scope effectively become session scope once there's a validation error.

I suspect that what happened was that the implementers of MyFaces decided to use the session as a temporary holding space for invalid values that can't be retrieved from the backing bean, forgetting that backing beans can also be request scope, thus introducing a bug caused by this inconsistency in scope.

My suspicion is that you aren't going to get a useful answer to this until you post your code. You said that the backing bean wasn't involved, but I suspect that it is. If you post both your JSP code and your backing bean code, you'll get better help.

Wally Hartshorn

Bagwan Mehrat
Ranch Hand

Joined: Jan 26, 2002
Posts: 119

posted Feb 08, 2006 11:19:00

0

You're right that I didn't post code before, since this is a general issue, and isn't specific to any particular piece of code, but I've written some code here that could help others recreate the problem, if they're interested in a quick and easy way of doing so.

In your submit method you could just say attrib=""; Or perhaps I'm not understanding your problem?

Bagwan Mehrat
Ranch Hand

Joined: Jan 26, 2002
Posts: 119

posted Feb 08, 2006 11:37:00

0

Originally posted by M Litherland: In your submit method you could just say attrib=""; Or perhaps I'm not understanding your problem?

I'm sorry, but I'm trying to understand your idea, and I'm drawing a blank. I can understand what you proposed to add, and where, but I'm not understanding what the aim of that code is?

Mike Litherland
Ranch Hand

Joined: Aug 12, 2004
Posts: 31

posted Feb 08, 2006 12:10:00

0

Well, you want to clear out that bean attribute after the user clicks submit, right? So after your process the value of attrib you set it to "" to clear it out, then it won't redisplay in your form.

Make sense?

Bagwan Mehrat
Ranch Hand

Joined: Jan 26, 2002
Posts: 119

posted Feb 08, 2006 12:19:00

0

Maybe this is getting a bit confusing. One of the reasons why I originally didn't want to post the code is because I thought it might confuse people, as it has, since the code itself is actually irrelevant, since when the validation error occurs, because the form data is invalid, the framework can, of course, no longer call the bean for data. So the problem is not with the attribute in the bean code that's posted here, but with the portion of the JSF framework that tries to substitute for the bean in the event of a validation error.

I was hoping that someone might know if this issue is something likely to be addressed in JSF 1.2 once the Java EE 5 standard is finalized? Or if someone knows a workaround to programatically clear the JSF framework's state in this case somehow?

Bagwan Mehrat
Ranch Hand

Joined: Jan 26, 2002
Posts: 119

posted Feb 08, 2006 15:10:00

0

I've been thinking a little bit more about the difference in scope between a request scope bean and the JSF framework, and I wonder if anyone could offer some thoughts on my following newbie points of conjecture on what's going on.

3. When a user enters an invalid value in a component, the UIInput's setValue() or maybe setSubmittedValue() gets set to the invalid value, and setValid(false) is also called.

4. Since validation failed, the backing bean is not called.

5. On subsequent requests, the previous UIViewRoot is still remembered, since it's session scope, and it also naturally remembers the invalid value in the UIInput.

6. When render is iterated over the component tree, the renderer can either get the value from the bean, or from the component tree. If the value is set in the UIInput, then that has precedence.

7. The above factors cause the JSF framework to get stuck on previously submitted invalid values for the duration of the session, even though the backing bean is request scope.

Does the above seem to make sense to anyone? If this is what's happening, I would appreciate any ideas for somehow fixing the component tree, or doing something to it on the fly to get around this problem.

Originally posted by Bagwan Mehrat: I am writing a JSP page that allows users to edit contacts. So if a user wants to edit contact #1, he goes to the page "/edit.jsf?id=1", or id=2, and so on.

I would say here is your problem...

JSF is not made to listen to such URL-parameters.

Originally posted by Bagwan Mehrat: To answer my own question, to work around this problem what I had to do was allow the user navigate back to the previous list page with a commandButton or commandLink. If the user navigates back using a plain outputLink or even using the browser Back button, JSF gets confused.

I wonder. Is that just his problem or does it reflect a problem with JSF in general? Like it or not, JSF applications are not deployed in isolation. Other pages on the web need to be able to link to JSF pages and they need to do so while providing parameters.

This is not a workaround, but the only correct way to do it...

I haven't tried this, but just a wild idea. You might use a binding on your <h:form> element to your backing bean( <h:form binding="testEdit.bind" /> ). The setBind method you specify here will be called at each page load, giving you the opportunity to act on this 'event'. In your binding funcion, you could check whether the mentioned GET parameters has been supplied. If it has, simply use the UIComponent that is handed to you to locate the component with ID attrib. Upon reaching this component, try to set its value to null.

I have no idea whether the binding method is called in time to reset the error state, but it might just work. I used this technique in the past to dynamically apply effects to components in my tree (e.g. changing the css attribute).