my dog learned polymorphism*
The moose likes JSF and the fly likes Re-Render Problem after ValidationException Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » JSF
Bookmark "Re-Render Problem after ValidationException" Watch "Re-Render Problem after ValidationException" New topic
Author

Re-Render Problem after ValidationException

Dominik Müller
Ranch Hand

Joined: Apr 28, 2009
Posts: 36
Hi all,

got here a "little" Problem:

Gerneral:
Is there any JSF-mechanism which interrupt the "normal" rendering phase of an Ajax-ReRender when (in @ViewScoped) a ValidationException is thrown before (at any time?)?
Have i to "reset"? an error-status or something like that?

The Problem:
Have an application with a calendar on top (which fill an textinput with an date and, which fires an JSF-Ajax Event to reload an Datatable with some InputFields. Look something like this:

JavaScript Call:


the input fields in the datatable/form looks like (where "zef" is the managedBean, and "maAufgabe" the one iterator var):


The ValidatorClass:


Application works fine:
1. select a Date
2. Ajax Call
3. refresh the Model (getter of "input" is called)
4. refresh view

Now the Problem:
5. enter a invalid input
6. validator throws a validation Exception
7. refresh view with Error Messages

8. select an other Date (without a submit, just again the ajax call)
9. Ajax Call
- without calling the validator again
10. the validator-field isnt't refreshed through the model
- all Fields in the refreshing-view without the validator get refreshed
11. response of the ajax call still shows the inputs of the invalid-try from the submit before.

12. after a submit without a Validation-Error: all work fine!

jsf seems to remember a Validation-Error-State when in "ViewScoped" an do not render the components in normal way.

I have no more ideas
Hope somebody can help
Dom
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16019
    
  20

I don't know if I completely understood that, but I'll try and help.

In the normal course of events, nothing can be done to the model unless all items pass validation. Validation failure loads up the JSF messages object, which can then be viewed using the JSF messages and JSF message for= tags.

It gets trickier when you do partial page updating. Only the parts of the page that are actually indicated will be submitted for update. To get rid of an item-level validation error message display, the "message for=" element has to be part of the reRender set, and the item being validated has to be part of the AJAX request, since otherwise it doesn't re-validate, and the item is considered to remain invalid.

The actual JSF messages object is created empty from scratch, so the validation message is consumed the first time it displays. However, on a partial page update, the display only changes the reRender regions, so a message that's on-screen only gets erased if it's part of the reRender set, even though it's no longer in the JSF messages object.


Customer surveys are for companies who didn't pay proper attention to begin with.
Dominik Müller
Ranch Hand

Joined: Apr 28, 2009
Posts: 36
Tim Holloway wrote: To get rid of an item-level validation error message display, the "message for=" element has to be part of the reRender set, and the item being validated has to be part of the AJAX request, since otherwise it doesn't re-validate, and the item is considered to remain invalid.


in my case even this happens already. After a very long study of the results from my favourite search engine i found this articel which faces exactly my problem:

ClearInputComponents

The Short-Version: after a validation Exception, JSF saves the invalid input directly to UIInputComponent (not the ManagedBean of Course). When i now call the Ajax-Request, JSF restores the old view, recognize the existing "pre-saved" value and takes the values from this saved-state an NOT from the Bean. > Thats the Problem. Until the Page gehts a Full-Reload or a "submit" (which returns in my case a null-navigation) this saved state remains at the UIComponent.

In the above mentioned articel there a some fixes for this issue, but until now, i can't get the code snipped working correct.
In fact i don't now where to implement these behviours. But lets take an Example of the solutions:



force jsf to explicit rebuild the view (?), ok looks good. But where to call this function? My first idea was to implement a phase listener, which hacks before the "Restore View" Phase, but i am working with an template an defining the phaselistener on the sub-page seems not invoking the "restoreView"-Phase (seems logical). But where else? My Ajax-Change-Event is fired over an InputField, here i have the options: by any Change-Listener or the Setter of the Attribute on the Bean, but both seems to be too late (?)

Some Ideas? (hope the problem is now a little clearer)
thanks a lot
Dom
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16019
    
  20

Well, I'm still murky on some things, but as I've said many a time, any time your app starts heavily referencing javax.faces classes (excluding datamodels), you're probably trying to do things the hard way.

If what you're attempting to do is restore corrupted data entry back to the original pre-corruption values, there are several options. One of the best is the good old-fashioned HTML "reset" button. But that will reset everything on the form, good, bad, AND indifferent.

Another approach would be to have some client-side JavaScript revert the values. I'm not real keen on that, because I don't like loading up pages with stuff that breaks if JavaScript has been disabled, but it's an option.

You should be able to add a "Cancel" button that does an immediate update without posting anything. A reRender on just the fields you want to revert should work. I think I've done this a few times, in fact.

And sometimes the best solution is just to use multiple forms on the page and treat them independently. Another old classic.
Dominik Müller
Ranch Hand

Joined: Apr 28, 2009
Posts: 36
Tim Holloway wrote:
If what you're attempting to do is restore corrupted data entry back to the original pre-corruption values,


Not really. I try again to make it a little bit clearer:

The default way it goes (which of course in most situtation work fine

We have a Object A (which have to fill with data)
a user gets a formular, enters invalid data, submit the form, get an error, correct the error, submit again, and the Object A gets an update.
(this works even in my case, but lets take a look here)

We have a Object A (which have to fill with data)
a user gets a formular, enters invalid data, submit the form, get an error
THEN
the User hit a button (Ajax), which results in replacing the DataObject. Now we haven't anymore Object A, but Object B (same Type, but a different one).
>again: we have now the same form, the same UIInputFields, the same View, the same ManagedBean-Object-Type which holds the date (of course), but a new instance of this Type.
The Problem at this point is, that the UIComponents doens't know anything about the instance of the data-holding Object, for the View the UIComponent have an error-state and JSF displays the old-values.

I do not want to process any invalid data, the opposite, i just want JSF after a specified event (in this case Ajax ReRender, or even an ActionListener) to throw away his PartitialState, the states Saves at the UIComponent and just simply build up a new component-tree and load the Data from the ManagedBean.

Many thanks
Dom
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16019
    
  20

I think it'll go faster if you look at what the actual (drooling) user is seeing instead of worrying about the internals of JSF. Attacking the lower levels prematurely can blind you to other possibilities.

What I think you said is that just because item "A" had bad data in the form, you don't care because you want to throw all that away and bring up an item "B" in the same form.
Dominik Müller
Ranch Hand

Joined: Apr 28, 2009
Posts: 36
Tim Holloway wrote:just because item "A" had bad data in the form, you don't care because you want to throw all that away and bring up an item "B" in the same form.


thats it. But i think for this behaviour i have to deal with the "internals" of JSF, but one simple solution whould be enough... an idea?

Dom
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16019
    
  20

I may still be missing something, but if you want to discard all input, just use an "immediate" button. It's specifically designed to bypass validation. Trivial. No JSF internals required.

The part I'm not sure of is how you determine "which" record will be Record B. If if's predetermined (for example, you're processing a set of records one by one), it's pretty easy. Just advance to the next record on the immediate button's action processor.

On the other hand, if you want to aim the browser at a record that the user selects as part of the process of discarding the previous edits, you should set up a completely independent form (NOTE: HTML forms cannot be nested). Don't use an immediate button in that case, use a regular command button so that the selection will be set (after validation!) by the JSF lifecycle process for ordinary forms submission.

In HTML (and therefore in JSF), when you submit a form, only that form gets submitted. None of the data on any of the other forms is submitted. Therefore, none of the other forms data is validated and therefore bad data on those forms will not block the processing on the form that you actually do submit. Or, to put it another way, you don't submit a page, you submit a form. That's one of the fundamental rules of HTML.

Where life gets confusing is when people try to have it both ways. You can include data from other forms on a submit, but only by using Javascript to make those items look like they're in the form actually being submitted. But at that point we've left HTML and gone into JavaScript Land, and if you needed something like that when using RichFaces, there are options that can be used to assist those sort of tricks.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16019
    
  20

Addendum:

If you do have a second form that submits the Record B ID, load up the properties for the record in the submit button's action processor. If you do a full-page update or the record detail form is part of your RichFaces reRender set, the updated backing bean values will then be reflected out to the user's browser, replacing the Record A values.

Just in case it wasn't apparent. You're not limited to updating only backing data that's associated with what came in from the submit process. Only constrained to ensure that if you do update other backing bean data that the parts of the page that display those items is refreshed.
Yaroslav Stavnichiy
Greenhorn

Joined: Nov 17, 2010
Posts: 2
Dominik,

Have you found a solution to this problem? I'm struggling with the same issue. The form gets stucked in invalid state so changes to the backing bean are not shown after ajax update.

Tim,

Your suggestion about second form for object B is not totally clear for me. How can I dynamically create new form on a page in place of old one?

My case is the following: on the lefthand side of page I have selector (a list of database records, h:selectOneListbox to be exact), on the righthand side I have a form to edit single record currently selected by the selector. Once I enter invalid value for a field in the form, subsequent changes to selector do not update the form anymore. Need to do browser refresh to get out of this.
Yaroslav Stavnichiy
Greenhorn

Joined: Nov 17, 2010
Posts: 2
Here is my solution:



I call this on the form UIComponent just before loading backing bean with new object. This clears all previously stuck values from the form allowing it to render values directly from new object. Works with PrimeFaces ajax (including partial view processing).
 
 
subject: Re-Render Problem after ValidationException