FormSchema class abstract

A base class for strongly-typed, aggregate form schemas.

What you must implement

  1. namedInputs — maps serialization keys to input instances.
  2. copyWith — field-level mutation (manual, Freezed, or build_runner).
  3. touchAll — marks every input touched via your copyWith.
  4. reset — resets every input to its initial value and increments formKey via your copyWith.

What you may override

Minimal example

class LoginSchema extends FormSchema {
  final EmailInput email;
  final PasswordInput password;

  const LoginSchema({
    this.email = const EmailInput.untouched(),
    this.password = const PasswordInput.untouched(),
    super.formKey,
  });

  @override
  Map<String, FormInput> get namedInputs =>
      {'email': email, 'password': password};

  LoginSchema copyWith({
    EmailInput? email,
    PasswordInput? password,
    int? formKey,
  }) => LoginSchema(
    email: email ?? this.email,
    password: password ?? this.password,
    formKey: formKey ?? this.formKey,
  );

  @override
  LoginSchema touchAll() => copyWith(
    email: email.markTouched(),
    password: password.markTouched(),
    // formKey unchanged — touchAll is not a reset
  );

  @override
  LoginSchema reset() => LoginSchema(
    // nextFormKey increments the counter → triggers widget recreation.
    formKey: nextFormKey,
  );
}

Using formKey to reset visible text without controllers

TextField(onChanged: ...) owns its text internally and ignores programmatic value changes after the first build. The only way to reset the visible text without a TextEditingController is to change the widget's key, which causes Flutter to destroy and recreate it.

Pass formKey as a ValueKey prefix on every text field:

// StatelessWidget — no TextEditingController, no StatefulWidget needed.
TextField(
  key: ValueKey('${state.schema.formKey}_email'),
  onChanged: cubit.emailChanged,
  decoration: InputDecoration(
    errorText: state.schema.email.displayError(state.status)?.message(context),
  ),
)

When reset is called the cubit emits a schema with an incremented formKey. Flutter sees a new key, destroys the old TextField, and creates a fresh one — visible text cleared, no controllers required.

Constructors

FormSchema({int formKey = 0})
const

Properties

changedValues Map<String, dynamic>
no setter
errors List
no setter
firstError → dynamic
no setter
formKey int
A monotonically increasing integer, incremented each time reset is called.
final
hashCode int
The hash code for this object.
no setterinherited
inputs List<FormInput>
no setter
invalidInputs List<FormInput>
no setter
isModified bool
no setter
isNotValid bool
no setter
isSchemaValid bool
no setter
isTouched bool
no setter
isUntouched bool
no setter
isValid bool
no setter
namedErrors Map<String, dynamic>
no setter
namedInputs Map<String, FormInput>
Maps serialization keys to their respective input instances.
no setter
nestedSchemas Map<String, FormSchema>
Sub-schemas embedded in this schema (address, billing, etc.).
no setter
nextFormKey int
Returns formKey + 1.
no setter
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
schemaErrors List
no setter
schemaValidators List<SchemaValidator>
Cross-field validation rules.
no setter
values Map<String, dynamic>
no setter

Methods

firstErrorOf<E>() → E?
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
populateFrom(Map<String, dynamic> data) FormSchema
Pre-fills all inputs from data and marks them touched.
reset() FormSchema
Returns a new schema with every input reset to its FormInput.initialValue and InputStatus.untouched, and with formKey incremented.
toString() String
A string representation of this object.
inherited
touchAll() FormSchema
Returns a new schema with every input marked InputStatus.touched.
validate() → (FormSchema, bool)
Touches all inputs then checks validity — the canonical submit guard.

Operators

operator ==(Object other) bool
The equality operator.
inherited