PDA

View Full Version : Clearing binding error


geggle
Oct 12th, 2006, 08:30 AM
Is there any way to "clear" binding errors for a field during validation?

I have a form which has of a dynamic list of rows as shown below:
349
Clicking Add adds a new row to the bottom of the list, clicking Delete removes all rows which are checked from the list.

The controller object is an extension of the SimpleFormController where the Add and Delete are implemented as a form change.

The regular expression field in each row comes from a java.util.regex.Pattern property.

If the user is deleting a row, any binding errors that occurr for fields in that row are not important, however binding errors for any other row should still be shown. I don't want to use supressBinding() for the deletion of a field action because any other edits that the user has made on the form will be discarded. Instead, what I would like to do is "clear" the binding errors for any fields that are to be deleted.

How can I acheive this behaviour?

Marten Deinum
Oct 12th, 2006, 08:42 AM
Instead of using supressBinding you could use suppressValidation :). Binding will still occur but no validation. Could that be a solution?

geggle
Oct 12th, 2006, 09:03 AM
Thanks for your reply!

Binding occurrs before validation, so the errors object is potentially already populated with an error even if suppressValidation() returns true.

Perhaps an example will help to illustrate what I mean.

Suppose that a user had created a new row and started to enter a regular expression then decided that they didn't want the new row. The row that they want to delete has an invalid regular expression. When the binding happens, a bind failure will occurr (because the property editor can't compile the regular expression) and the form will have a BindException, which will mean that change action won't happen. I'd like to stop a bind failure on that row causing the form to be redisplayed in this case.

Marten Deinum
Oct 12th, 2006, 09:13 AM
Oops... Mistaken validation errors with binding errors... That is 2 misreads in 2 days. :|

In that case you probably can override the onBind method. I guess you can then clear the BindException object. I'm just in doubt what happens when a bind exception occurs. Does it continue with the other fields or just quits binding.


protected void onBind(HttpServletRequest request, Object command, BindException errors) throws Exception


Just checked the BindException class and is doesn't have a clear/empty method. However I still think that one of the onBind methods is the way to go.

geggle
Oct 12th, 2006, 09:25 AM
Some piccies to help visualisation.

Suppose the user, Mr Brain Death, is working my my super fantastic application :)

Mr Death has this initial view:
350

Mr Brain Death clicks on Add and adds a new row:
351

Then Mr Death starts to enter some new information into the new row and edit the existing rows:
352

Now Mr Death realises that he doesn't actually need the new row, and gets ready to delete it by checking the "delete" checkbox:
353

When Mr Death clicks on the Delete button, I want the result to be:
354

However, this doesn't happen. Because of the binding process on the regular expression field, the bad regular expression - "(" - in the last row (which is going to be discarded) will mean that the onFormChange() callback doesn't happen. Instead, the form is re-displayed with the binding error shown for the regular expression field on the last row (sorry, don't have a picture of this one handy).

geggle
Oct 12th, 2006, 09:28 AM
In that case you probably can override the onBind method.
Thanks for this, looks like it might be an option worth trying. I'll have a look and see whether this will do the trick.

geggle
Oct 12th, 2006, 09:37 AM
Alas, there isn't any way to "clear" an existing error in the BindException class (the errors list is essentially add-only).

Marten Deinum
Oct 12th, 2006, 09:43 AM
As I already stated :). Alas but I think the onFormSubmission method can come to the rescue.


/**
* This implementation calls <code>showForm</code> in case of errors,
* and delegates to <code>onSubmit</code>'s full version else.
* <p>This can only be overridden to check for an action that should be executed
* without respect to binding errors, like a cancel action. To just handle successful
* submissions without binding errors, override one of the <code>onSubmit</code>
* methods or <code>doSubmitAction</code>.
* @see #showForm(HttpServletRequest, HttpServletResponse, BindException)
* @see #onSubmit(HttpServletRequest, HttpServletResponse, Object, BindException)
* @see #onSubmit(Object, BindException)
* @see #onSubmit(Object)
* @see #doSubmitAction(Object)
*/
protected ModelAndView processFormSubmission(
HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)
throws Exception {

if (errors.hasErrors()) {
if (logger.isDebugEnabled()) {
logger.debug("Data binding errors: " + errors.getErrorCount());
}
return showForm(request, response, errors);
}
else if (isFormChangeRequest(request)) {
logger.debug("Detected form change request -> routing request to onFormChange");
onFormChange(request, response, command, errors);
return showForm(request, response, errors);
}
else {
logger.debug("No errors -> processing submit");
return onSubmit(request, response, command, errors);
}
}


You could override it, check for errors (and the action delete) if both are true then make a call to whichever method you like. Else call super.onFormSubmittion().

geggle
Oct 12th, 2006, 09:57 AM
As I already stated :).
Whoops, now it's my turn to feel stupid... missed the last crucial line of your previous post. Doh! ;)
...but I think the onFormSubmission method can come to the rescue.
Perhaps this will be the solution. Thanks! :D

geggle
Oct 12th, 2006, 09:59 AM
Oh yeah, it just occurrs to me that I forgot to mention this is in a Portlet, and thus I'm using the Portlet MVC implementation. Gee I'm scatterbrained today!

geggle
Oct 13th, 2006, 07:47 AM
Well, I've looked into this a little more and I don't think processFormSubmission() is going to work as a possible place to "clear" binding errors. The issue is the "add-only" nature of the BindException object (the errors). It appears to be an implicit assumption of the implementation that you only want to put additional errors into the BindException. At the processFormSubmission() stage, the errors are already set and can't be modified, so intercepting at this point isn't going to help.

If it were possible to modify the BindException object, then I could use processFormSubmission() to accomplish the required result.

Binding and validation occurrs in bindAndValidate(), but I can't override this method because it's final.

Perhaps what I really need to do is mess about with the binder to see whether I can handle it there, but that seems to me to be at too low a level to make sense!

Any other ideas anyone? The cleanest I can see is to implement a modification to the existing BindException.

geggle
Oct 13th, 2006, 08:12 AM
Rather than butcher BindException, what I could do is:


Create a subclass of BindException (say EditableBindException) that is editable, .
Create a subclass of PortletRequestDataBinder (say EditablePortletRequestDataBinder) that overrides the createErrors() method to create an EditableBindException instead of BindException.
Override the createBinder() method in my controller class to create the EditablePortletRequestDataBinder instead of the PortletRequestDataBinder
In my validator, check for an EditableBindException and clear the errors for the deleted fields.


That might work!

geggle
Oct 13th, 2006, 08:19 AM
... and that's great, except the errors field in the BindException is private! :mad:

Back to the drawing board!

Marten Deinum
Oct 13th, 2006, 08:28 AM
You don't have to clear the BindErrors object. If you override the processFormSubmission() method like the code below it should work.


protected ModelAndView processFormSubmission(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception {

/* Check if the action is delete and check if we have errors,
* if that is the case we still need to execute our delete method.
* if not, just proceed with what we were doing.
*/

if (WebUtils.hasSubmitParameter(request, "delete") && errors.hasErrors()) {
doDeleteInternal(request, response, command);
}

return super.processFormSubmission(request, response, command, errors);
}


I made the following assumptions:

You use a submit button
Displaying your errors occurs an a per field basis instead of on big block with error messages.


Maybe even better always handle your delete rows in the processFormSubmission method. That way you have one place where your delete functionality is handled.

geggle
Oct 13th, 2006, 09:02 AM
You don't have to clear the BindErrors object.

Now I understand what you were getting at! Allow the bind and validate to occurr as normal, do the delete action as a special case and allow "bogus" errors to get to the view but don't show them because the associated field isn't there.

It works beautifully, thanks a bunch!

As you imply, if I just printed errors as a block at the top I'd get messages about fields that were just deletec, but with the errors displayed next to the fields present on the form only, it's fine.

Tony.