I'm receiving the following error message:
══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════ The following assertion was thrown while dispatching notifications for ErrorTextNotifier: setState() or markNeedsBuild() called during build. This _InheritedProviderScope<ValidityNotifier?> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase. The widget on which setState() or markNeedsBuild() was called was: _InheritedProviderScope<ValidityNotifier?> The widget which was currently being built when the offending call was made was: This is my code (I've had to omit a bunch of the code) TextFormField
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => ValidityNotifier(),
child: Builder(builder: (context) {
return Column(
children: [
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (str) {
var validity = //custom validity function
Provider.of<ValidityNotifier>(context, listen: false).setValidity(validity);
return null;
},
),
Consumer<ValidityNotifier>(builder: (context, model, child) {
if (model.isValid) {
return Text("Custom Validity Message")
}
return const SizedBox.shrink();
}),
],
);
}),
);
}
}
class ValidityNotifier extends ChangeNotifier {
bool _isValid = false;
bool get isValid => _isValid;
void setValidity(bool isValid) {
_isValid=isValid;
notifyListeners();
}
}
I want the state to be changed every time the validation function is called, I've considered adding a listener to a TextEditingController but it would trigger a rebuild every time an input is made.
CodePudding user response:
As the error message says you have concurrent builds running. When you call setValidity
which triggers a rebuild due to notifyListeners
, Flutter is already in the process of building the TextFormField
.
You can use a post frame callback, in this case the setValidity
method call will run only once the current build is finished.
Instead of:
Provider.of<ValidityNotifier>(context, listen: false).setValidity(validity);
Try this:
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<ValidityNotifier>(context, listen: false)
.setValidity(validity);
});
CodePudding user response:
Inside TextFormField
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) => value!.isEmpty ? "Your special string here" : null