Flutter TextFormField onSave() doesn’t get called after successful validation

By | October 9, 2023

I have a weird problem in flutter TextFormField. I implemented form validation in TextFormField. But onSaved() function doesn’t get called after successful validation.

First I created basic Widget using TextFormField

— In AppWidgets class —

  static Widget buildTextFormField(
    String labelText,
    String helperText,
    IconData prefixIcon, {
    Widget suffixIcon,
    bool obscureText = false,
    TextInputType keyboardType = TextInputType.text,
    TextInputAction textInputAction = TextInputAction.none,
    FocusNode focusNode,
    ValueChanged<String> onFieldSubmitted,
    TextEditingController controller,
    FormFieldValidator<String> validator,
    FormFieldSetter<String> onSaved,
    bool isLightTheme = false,
  }) {
    return Theme(
      data: isLightTheme
          ? AppThemesLight.textFormFieldThemeData
          : AppThemesDark.textFormFieldThemeData,
      child: TextFormField(
        controller: controller,
        validator: validator,
        onSaved: onSaved,
        keyboardType: keyboardType,
        textInputAction: textInputAction,
        focusNode: focusNode,
        onFieldSubmitted: onFieldSubmitted,
        obscureText: obscureText,
        decoration: InputDecoration(
          filled: true,
          fillColor: isLightTheme
              ? AppColorsLight.textFieldFillColor
              : AppColorsDark.textFieldFillColor,
          labelText: labelText,
          helperText: helperText,
          border: OutlineInputBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(AppDimensions.textFieldBorderRadius),
            ),
          ),
          prefixIcon: Icon(
            prefixIcon,
            color: isLightTheme
                ? AppColorsLight.primaryTextColor
                : AppColorsDark.primaryTextColor,
          ),
          suffixIcon: suffixIcon,
        ),
      ),
    );
  }

From that, created email text from field.

  static Widget buildEmailTextFormField(LoginState loginState) {
    return AppWidgets.buildTextFormField(
      'Email address',
      'Your email address',
      Icons.email,
      keyboardType: TextInputType.emailAddress,
      textInputAction: TextInputAction.next,
      focusNode: loginState.focusNodes[0],
      onFieldSubmitted: (String value) {
        print('submitted $value');
        loginState.onFocusChanged(index: 0);
      },
      validator: (String email) {
        print('validator $email');
        return InputValidators.validateEmail(email);
      },
      onSaved: (String email) {
        print('saved $email');
        loginState.email = email;
      },
    );
  }

Here is the email validator I used.

  static String validateEmail(String email) {
    Pattern pattern =
        r'^(([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$';
    RegExp regex = new RegExp(pattern);
    if (email.isEmpty)
      return 'Email can't be empty';
    else if (!regex.hasMatch(email))
      return 'Enter valid email address';
    else
      return null;
  }

I tested above code by putting print statement inside onSaved() function, but it’s not printing after successful validation.

Best Solution

The onSaved() function won’t be called automatically after successful validation. We have to call _formKey.currentState.save() manually to save our variables.

Form(
  key: key,
  child: TextFormField(
    onSaved: (val) {
      print('saved');
    },
    validator: (val) {
      print('validating');
    },
  ),
),
RaisedButton(
  child: Text('Click me'),
  onPressed: () {
    if (key.currentState.validate()) {
      key.currentState.save();
      print('valid');
    }
  },
),