Class BinderCustomField<T>

Type Parameters:
T - field value type
All Implemented Interfaces:
AttachNotifier, BlurNotifier<CustomField<T>>, DetachNotifier, Focusable<CustomField<T>>, FocusNotifier<CustomField<T>>, HasElement, HasEnabled, HasHelper, HasLabel, HasSize, HasStyle, HasTheme, HasValidation, HasValue<AbstractField.ComponentValueChangeEvent<CustomField<T>,T>,T>, HasValueAndElement<AbstractField.ComponentValueChangeEvent<CustomField<T>,T>,T>, HasTooltip, HasValidationProperties, InputField<AbstractField.ComponentValueChangeEvent<CustomField<T>,T>,T>, Serializable, ValidatingField<AbstractField.ComponentValueChangeEvent<CustomField<T>,T>,T>
Direct Known Subclasses:
FieldBuilderCustomField

public abstract class BinderCustomField<T> extends CustomField<T> implements ValidatingField<AbstractField.ComponentValueChangeEvent<CustomField<T>,T>,T>
Support superclass for CustomFields containing sub-fields that are managed by an internal Binder.

As with many CustomField's, this class this allows editing a complex value type as a single bound property using multiple sub-fields. A common example is a date range value, which is a composite of two LocalDate values representing start and end date.

The purpose of this class is to add an internal Binder so that the individual sub-fields can be properly (and separately) validated. This class also includes support for validating the overall value, for example, requiring the date range start date to be prior to the end date.

Binding

Although a BinderCustomField may be bound as a field to a property in some larger containing class' Binder, each BinderCustomField also contains its own internal Binder to which its private sub-fields are bound.

Subclasses can customize this internal Binder by overriding createBinder().

Field Value

The value of a BinderCustomField is generated by creating a new bean instance and then applying the values of the internal sub-fields to it.

In order for this class to create new instances, its value type must have a public zero-arg constructor; otherwise, the subclass must override createNewBean().

In any case, the value of a BinderCustomField remains its empty value as long as any of its sub-fields remain in an invalid state according to the internal Binder.

Binders and Validation

Individual sub-fields are validated normally using the internal Binder; however, this guarantees only that the sub-fields are valid. It does not validate this BinderCustomField's value, which is derived from a combination of the sub-fields; normally, that's the responsibilty of some outer Binder, not the internal Binder.

Subclasses can override validate() to implement "whole bean" validation contraints on this BinderCustomField's value. However, for whole bean validation to have any effect, some code must register the validation provided by validate() to the outer binding. This happens automatically when this field is created by a FieldBuilder, or by any other mechanism which recognizes the ValidatingField interface (which this class implements). In particular, it's possible to recursively nest BinderCustomField's using FieldBuilder annotations and have proper validation at each level.

See also WholeBeanValidator for another way to do "whole bean" validation using JSR 303 validation constraints.

Layout

For layout, BinderCustomField simply concatenates the sub-fields into a HorizontalLayout. Subclasses can customize this behavior by overriding layoutComponents().

Example

See FieldBuilderCustomField for an example.

See Also:
  • Field Details

    • modelType

      protected final Class<T> modelType
      The field value type.
    • binder

      protected final Binder<T> binder
      The binder that is bound to this instance's sub-fields.
    • subfieldValidationErrors

      protected boolean subfieldValidationErrors
      Whether any sub-fields currently have a validation error.
  • Constructor Details

    • BinderCustomField

      public BinderCustomField(Class<T> modelType)
      Constructor.
      Parameters:
      modelType - field value type
      Throws:
      IllegalArgumentException - if modelType is null
  • Method Details