ULC Form Model

Purpose

ULC is perfectly suited for implementing form-based application that demand rich user interface features. ULC follows the model-view-controller pattern. In case of a form-based application the model is usually a JavaBean and as a developer you have to come up with some mechanism to read the data from the bean and fill in the form components. On saving the form this mechanism has to get all the data from the form components and write it into the bean. For a simple form this is no big deal, but if you have a number of extensive forms this can be quite cumbersome.

This contribution proposes a form model adapter which takes care of populating the form components with the bean data and writing the contents of the form back to the bean. In particular, the features are:

  • A generic adapter for reading from/writing to a bean.
  • Form-based synchronous bean updates or asynchronous property updates.
  • Form model provides a ULCHasChangedEnabler, perfectly suited for controlling save and cancel buttons attached to the form.
  • Form components supported: ULCTextComponent, ULCToggleButton, ULCSlider, and ULCComboBox.
  • Flexible mappings between form component and bean property, e.g. multiple ULCRadioButtons can be mapped to a single bean property
  • Simple interface to register a form component and map it to a bean property
  • New form component types can easily be added (provide a component adapter and extend the adapter factory)
Demo application usage: Upon start-up the form is disabled. Press "New" to create a new client record. Now the form is enabled and can be filled in. When pressing save the bean properties are shown in a dialog.

How to use

Simple use

In simple forms you just create an instance of FormModel, pass the bean and register each form component with the form model:

FormModel formModel = new FormModel(new Person());
ULCTextField firstName = new ULCTextField(20);
formModel.registerSource(Person.FIRST_NAME, firstName);

This code snippet shows how to create a new bean, save the form input to the model, reset the HasChangedEnabler, and clear the form afterwards:

formModel.newModel();
//…

formModel.saveInput();
formModel.reset();
formModel.clearModel();

For flexible error handling an IFormModelErrorHandler can be optionally passed to the form model. By default, the form model does not report any errors.

Sophisticated use

You can always derive a class from FormModel and fine-tune its behaviour. Examples are:
  • Specify how to clear the form
  • Creation of a new bean
  • Interception of component changes
A typical application of interception is a form where the user enters a key. When leaving the input field the application looks up a value (e.g. in a database) and feedbacks this value into the form. This has to be done asynchronously in order to improve the responsiveness of the application.

For this you have to override the method propagateSourceToModel in a subclass of FormModel. The feedback value does not necessarily have to be a property of the bean model.

protected void propagateSourceToModel(IFieldAdapter fieldAdapter) {

    super.propagateSourceToModel(fieldAdapter);
    if (fieldAdapter.getProperty().equals(Person.CUSTOMER_TYPE_CODE)) {
        propagateValueToSource(CUSTOMER_TYPE, getPerson().getCustomerType(fieldAdapter.getStringValue()));
    }
}

The input form components have to be registered like this:

customerTypeCode = new ULCTextField(1));
customerType = new ULCTextField(10);
customerType.setEnabled(false);
personModel.registerSource(Person.CUSTOMER_TYPE_CODE, customerTypeCode, true, true);
personModel.registerNonModelSource(PersonModel.CUSTOMER_TYPE, customerType);

As shown above the customer type field is not a bean property but provided by some lookup table.

Form model adaptation

If you would like to integrate a component of your own you have to implement a field adapter, extend the field adapter creation, and provide a registration method in FormModel. A field adapter implements the IFieldAdapter interface and realizes the mapping between a form component and the bean.

How it is implemented

The field adapters make use of the Commons BeanUtils classes which provide dynamic access to Java object properties. The form model just maintains a list of field adapters which map a form's elements to a bean's properties.

Resources