Blog About Contact

Implementing a "Draft Mode" with Apache Wicket Forms

Published Wed, 20 Oct 2010 • 3 comments

A question came up on wicket-users recently about whether it's possible to implement a form in Wicket whereby you can bypass the validation temporarily so that users could save prior to submitting the form.

Think something along the lines of "save draft" in a mail client like GMail.

It's possible but requires a bit of Wicket-foo. I did post a short snippet on the mailing list, but I thought a longer explanation might be helpful.

First of all, let's get something out of the way; it's not possible to accept data that the model backing your components do not accept.

For example, you can't accept "asdf" into a model field backed by an Integer - it ain't going to work whichever way you slice it. (Though, you can accept any input if you build a model that consists only of Strings and add validation for numerics etc. further down the line).

Here's the key steps to making a "draft mode" Wicket form -

  1. Override the form's process() method to set a "draft mode" flag based on the component that submitted the form.
  2. Create validators that apply based on the mode that form is in.
  3. You're probably going to have multiple submit buttons on the screen which do different things, thus your form's onSubmit() handler will probably do nothing.

This means that you can't use Wicket's built in validators as they are applied regardless of any notion of "mode" that you may have in your form.

Here's an example of how this might hang together:

class MyForm extends Form {
    private final SubmitButton submitButton;
    private final SubmitButton saveDraftButton;
    private final TextField textField;
    private boolean draftMode = true;

    public MyForm(String id) {
        super(id);
        add(textField = new TextField("textField"));
        add(saveDraftButton= new SubmitButton("draft") {
            @Override
            public void onSubmit() {
                myService.saveDraft(); // or whatever
            }
        });
        add(submitButton = new SubmitButton("submit") {
            @Override
            public void onSubmit() {
                myService.submit(); // or whatever
            }
        });
        // works like a required field validator
        textField.add(new IValidator() {
            @Override
            public void validate(IValidatable validatable) {
                if (validatable != null && !MyForm.this.draftMode && 
                    validatable.getValue() == null || validatable.getValue().toString().equals("")) 
                {
                    validatable.error(new IValidationError() {
                        public String getErrorMessage(IErrorMessageSource messageSource) {
                            return "Required.";
                        }
                    });
                }
            }
        });
    }

    @Override
    public void process(IFormSubmittingComponent submittingComponent) {
        draftMode = !(submittingComponent == submitButton);
        super.process(submittingComponent);
    }

    @Override
    public void onSubmit() {
        // do nothing
    }
}

This work can be standardised in your own sub-class of Form for example, with a bunch of validators that integrate with it.

Also, you can support even more complex use-cases by using a "mode" enum instead of a simple "draft" boolean. And make all the validators conditional on Mode.

This approach works just fine, but it would be nice if there was some sort of formal abstraction in Wicket to do this, since the current approach assumes quite a bit about the type of applications that will be implemented.


About the Author

Richard Nichols is an Australian software engineer with a passion for making things.

Follow him on twitter or subscribe by RSS or email.

You might also enjoy reading -


Discuss / Comment

There are 3 comments.

Add a comment

  • {{e.error}}

Thanks for your comment!/

Required.
Valid email address required.
Required.
Posting message, please wait...