Home > Mobile >  How to rebuild a widget whenever the validation function is triggered in TextFormField Flutter?
How to rebuild a widget whenever the validation function is triggered in TextFormField Flutter?

Time:01-25

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
  • Related