Customization
Most of the customization of the form is done through the annotations of the serializable classes.
The layout of the form is determined by the @Form
annotation, specifically the FomrDecorator
parameter, both of the @AutoForm
annotation as well as the DogsForm
widget.
Example
@serializable
@AutoForm(decorator: AddressDecorator())/*(4)!*/
class Address {
@AutoFormField(flex: 6)
final String street;
@AutoFormField(flex: 3/*(2)!*/)
final String city;
// No @AutoFormField required (1)
@LengthRange(min: 5, max: 5)/*(3)!*/
final String zip;
Address(this.street, this.city, this.zip);
}
class AddressDecorator extends FormColumnDecorator<Address> {
const/*(7)!*/ AddressDecorator();
@override
void decorate(BuildContext context, FormStackConfigurator configurator) {
configurator.row(["street", "city", "zip"]);/*(5)!*/
return super.decorate(context, configurator);/*(6)!*/
}
}
- You don't have to use the
@AutoFormField
annotation if you don't want to apply any additional visual customization to the field. - This field will be rendered with a flex of 3 inside the row specified by the
AddressDecorator
. - Specifying the length range of the zip field will automatically add a validator to the field.
- Here, we tell to dogs_forms to use the
AddressDecorator
as a default to render the form. Otherwise, the default decorator would be used. - We now tell the decorator to render all the fields in a row, respecting their flex values specified
in the
@AutoFormField
annotation. - You normally call the
super.decorate
method at the end of your decorator to automatically add fields you forgot to customize manually. - The decorator should be const, so that you can use it as an argument to the
@AutoForm
annotation.
My customization annotations are getting to long!
If your annotations are getting to long, you can extract the form logic into a separate serializable class and use the projection capabilities of dogs to convert between the two. This helps keeping your original serializable class clean and readable.
Otherwise, you can also use custom factories to create your form fields. There, you can isolate the logic without having to create really long annotations. Since this is relatively easy to refactor aftwards, you can always start with the annotations and refactor later.
To find out all the customization options, head to the [API Reference] for the @AutoForm
and
@AutoFormField
annotations. A few of the most important ones are listed below:
Important Options
AutoFormField.title
The title of the field, that will be used as the labelText for most form fields. If you want to localize this later, you can also specify 'titleTranslationKey'.
AutoFormField.subtitle
The title of the field, that will be used as the labelText for most form fields. If you want to localize this later, you can also specify 'subtitleTranslationKey'.
AutoFormField.factory
Specify a custom factory used to create the form field. If you generally want to use a custom factory for all fields of a specific datatype, consider customizing the mode factory registration in your main method by using a composed mode factory with your custom type bound factory.
AutoFormField.initializer
Specify a custom initializer used to create the initial value of the form field.
If you want to specify a custom initializer for items of iterable fields, use the itemInitialzer
parameter instead.
AutoFormField.decoration
Specify a custom decoration used to decorate the form field.
Decorators
Decorators are used to specify the layout of the form. The default decorator is the FormColumnDecorator
,
which uses an imperative builder approach to specify the layout of the form. The builders pushes
the fields into a list in the order you call the builder methods. Possible builder methods are:
Row
Rows are specified by calling the row
method of the FormStackConfigurator
class. The row method
takes a list of field names as an argument. The order of the fields in the list determines the order
of the fields in the row. The flex values of the fields and constraints are respected, so that the
fields are rendered with the correct width.
Wrap
Wraps are specified by calling the wrap
method of the FormStackConfigurator
class. The wrap method
takes a list of field names as an argument. The order of the fields in the list determines the order
of the fields in the wrap. The constraints of the fields are respected, so that the fields are rendered
with the correct width and height.
Single Field
You can also push a single field by calling the field
method of the FormStackConfigurator
class.
This will add the field to the form column, respecting the constraints of the field.
Push Widget
You can also push any arbitrary widget by calling the push
method of the FormStackConfigurator
class.
Field Builders
In case you want to use your own container widgets, you can build individual fields using the
buildField
and the buildFlexibleField
methods of the FormStackConfigurator
class. These
methods take a dog field and a BuildContext as an argument and return the built widget.
You can retrieve the dog field for a specific field name by calling the popNamed
method of the
FormStackConfigurator
class. This also automatically removes the field from the remaining fields.
Access BuildContext
You can retrieve the current BuildContext by using the context
field of the FormStackConfigurator
.