Validation and commit(): recommended recipe?

I have a Form. It is set to immediate mode, and writeThrough is false.

I’m looking for the best sequence of calls to validate the form while preventing various runtime exceptions from being thrown.

Currently, I have a button that is wired directly to the commit() method. This has the effect as you would expect of causing the form to validate before the commit takes place. It also results in an InvalidValueException being thrown. Currently I’m not catching this exception.

It occurs to me that I should probably call isValid() first, to see if the commit should proceed. But then I thought: why isn’t this built into the Form already? And then I thought, perhaps there is some way that I’m missing that makes this whole process even simpler (as is usually the case with this great library).

So: how do people normally kick validation off in their Forms?

Thanks,
Laird

The solution here that, as far as I can see, results in the least code duplication is to do this in my commit() method:


try {
  super.commit();
} catch (final InvalidValueException ive) {
  return;
}
// my value-added commit logic goes here

Now that makes me queasy, but Form#commit() will indicate failure only by throwing an InvalidValueException(), and will do so only after Form#isValid() has been called, as well as Form#validate(). I have no desire to duplicate this sequence of events, so the only way I can see to reuse them is to simply catch and ignore the resulting InvalidValueException (I ignore it since after all the errors will be chucked back to the user; if I don’t ignore it I get an exclamation point in my Save button that’s wired to the commit() method).

Is there a better way?

Best,
Laird

Hi Laird,

Not sure if a response is still useful, but the app I’m currently developing has a similar requirement, and I needed to minimise code duplication. Specifically:

  • I have multiple forms that need a standard button bar (Save, Cancel etc)
  • the button bar has standard behaviour across all forms
  • Save should only commit() when the forms are valid

To avoid duplicating code, I encapsulated the standard behaviour into a reusable ClickListener, and each time I create the button bar I give it a new instance of the listener (which is itself initialised with a list of ‘Buffered’ objects that can be commit()'ed, of which Form is one).

The factory method for my standard ClickListener is as follows:

   public static ClickListener createStandardClickListener(final Buffered... dataBuffers)
   {
      ClickListener listener = new ClickListener() {
         @Override
         public void onSave(Button button) {
            boolean haveValidInput = true;
            for(Buffered b: dataBuffers) {
               if(b instanceof Validatable) {
                  haveValidInput = haveValidInput && ((Validatable) b).isValid();
               }
            }
            if(haveValidInput) {
               boolean commited = false;
               for(Buffered b: dataBuffers){
                  if(b.isModified()) {
                     b.commit();
                     commited = true;
                  }
               }
               String notification = commited ?
                  "Changes saved successfully." : "No changes made.";
               button
                  .getApplication().getMainWindow()
                  .showNotification(notification);
            } else {
               button.getApplication().getMainWindow().showNotification(
                  "Invalid Input: Please ensure all required fields contain valid data before saving.",
                  Notification.TYPE_WARNING_MESSAGE);
            }
         }

         @Override
         public void onCancel(Button button) {
            for(Buffered b: dataBuffers){
               b.discard();
            }
         }
      };

      return listener;
   }

Note the method accepts an arbitrary number of Buffered objects. This is useful when you have multiple forms (or any other Buffered object) on the UI that share the same button bar, and you want a Save or Cancel to affect all of them.

My standard button bar then invokes the listener’s onSave()/onCancel() when the relevant button is clicked.

cheers.