attach method
FutureOr<ValidationResult?>
attach(
- BuildContext context,
- FormFieldHandle handle,
- Object? value,
- Validator? validator, [
- bool forceRevalidate = false,
Attaches a form field to this controller.
Registers the field and runs initial validation if a validator is provided. Manages field lifecycle transitions (initial → changed) and coordinates revalidation of dependent fields.
Parameters:
context(BuildContext, required): The build context.handle(FormFieldHandle, required): The field handle to attach.value(Object?, required): Current field value.validator(Validator?, optional): Validation function.forceRevalidate(bool, default:false): Force revalidation even if unchanged.
Returns: FutureOr<ValidationResult?> — validation result if applicable.
Implementation
FutureOr<ValidationResult?> attach(BuildContext context,
FormFieldHandle handle, Object? value, Validator? validator,
[bool forceRevalidate = false]) {
final key = handle.formKey;
final oldState = _attachedInputs[key];
var state = FormValueState(value: value, validator: validator);
if (oldState == state && !forceRevalidate) {
return _validity[key]?.result;
}
var lifecycle = oldState == null
? FormValidationMode.initial
: FormValidationMode.changed;
_attachedInputs[key] = state;
// validate
var future = validator?.validate(context, value, lifecycle);
if (future is Future<ValidationResult?>) {
_validity[key] = _ValidatorResultStash(future, lifecycle);
future.then((value) {
// resolve the future and store synchronous value
if (_validity[key]?.result == future) {
_validity[key] = _ValidatorResultStash(value?.attach(key), lifecycle);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (_disposed) {
return;
}
notifyListeners();
});
}
});
} else {
_validity[key] = _ValidatorResultStash(future, lifecycle);
}
// check for revalidation
Map<FormKey, FutureOr<ValidationResult?>> revalidate = {};
for (var entry in _attachedInputs.entries) {
var k = entry.key;
var value = entry.value;
if (key == k) {
continue;
}
if (value.validator != null && value.validator!.shouldRevalidate(key)) {
var revalidateResult =
value.validator!.validate(context, value.value, lifecycle);
revalidate[k] = revalidateResult;
}
}
for (var entry in revalidate.entries) {
var k = entry.key;
var future = entry.value;
var attachedInput = _attachedInputs[k]!;
attachedInput = FormValueState(
value: attachedInput.value, validator: attachedInput.validator);
_attachedInputs[k] = attachedInput;
if (future is Future<ValidationResult?>) {
_validity[k] = _ValidatorResultStash(future, lifecycle);
future.then((value) {
if (_validity[k]?.result == future) {
_validity[k] = _ValidatorResultStash(value?.attach(k), lifecycle);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (_disposed) {
return;
}
notifyListeners();
});
}
});
} else {
_validity[k] = _ValidatorResultStash(future, lifecycle);
}
}
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (_disposed) {
return;
}
notifyListeners();
});
return _validity[key]?.result;
}