If you have a complex object with several fields that themselves might be complex objects it can be hard to figure out where to place the validation logic to ensure that the object at the point of the form submission is correct.
For example if you have an IModel<User> and then want to tie each property of the User object to a form field. But if you use a property model directly it can be hard to ensure that the field itself is valid. Sometimes you want to validate two fields of the object and using the PropertyModel or CompoundPropertyModel directly can cause problems.
By creating a custom component that extends FormComponentPanel<T> you can internalize the complexity of validating an object so that at the level where it is used the concerns can be specified in terms of IModel<User> instead of the interior objects that make up a User object.
UserEditPanel extends FormComponentPanel<User>
Given a User object of:
We want to validate each field individually.
We only implemented for one field but you can see the pattern; each field in the User object is mapped to a FormComponent in the UserEditPanel. We can validate each field individually. The models for the fields are not linked so changes only propagate into the real valid model via the UserEditPanel.convertInput() method.
Then only when all fields are valid will we convert the values on those sub-components into an instance of the User object. Note that after convertInput has been called UserEditPanel model object has not yet been updated. Only after any IValidator<User>'s on the UserEditPanel itself pass will the model object be set to the new value.
Using the UserEditPanel
By encapsulating the User object creation and validation logic within the Panel you can just use the form like this:
The user of the UserEditPanel doesn't need to care about the internals of the component. If there is a problem the validation phase will fail and a feedback message generated. Only when the field details have been implemented correctly will the form.onSubmit() method be called and the userEditPanel.getModelObject() return the fully constructed User instance.