简体   繁体   中英

How to pass a validator to the `TextFormField' in Flutter?

I am dynamically generating textfields for my forms, in my flutter app. Please check below code

Widget _buildInputFields(
    String label,
    TextEditingController textController,
    TextInputType textInputType,
    IconData icon,
    Color iconColor,
  ) {
    return Container(
        margin: EdgeInsets.only(left: 20, bottom: 20),
        child: Container(
          padding: EdgeInsets.only(right: 20),
          child: Row(
            children: <Widget>[
              Flexible(
                child: TextFormField(
                  controller: textController,
                  validator: (value) {
                    if (value.isEmpty) {
                      return 'Please enter some text';
                    }
                  },
                  style: new TextStyle(color: Colors.white),
                  keyboardType: textInputType,
                  decoration: InputDecoration(
                      labelText: label,
                      fillColor: Colors.white,
                      labelStyle: TextStyle(
                          color: Colors.white, fontWeight: FontWeight.w600),
                      enabledBorder: OutlineInputBorder(
                        borderSide:
                            const BorderSide(color: Colors.white30, width: 2.0),
                        borderRadius: BorderRadius.circular(25.0),
                      ),
                      suffixIcon: IconButton(
                        icon: Icon(icon, color: iconColor),
                        onPressed: () {},
                      )),
                ),
              ),
            ],
          ),
        ));
  }

The above method returns a TextFormField with the styling I need, so I don't have to recode it hundreds of times. I just call the method and I get a new TextFormField

Anyway, I need to do form validation and every field has a different validation.In flutter, how can I pass a validator to the textformfield ?

You can simply pass the validator as an argument just as you have done to the others. All you need is to pass in a function that takes a String as an argument and returns a String too.

//username validator possible structure
   Function(String) usernameValidator = (String username){
        if(username.isEmpty){
          return 'Username empty';
        }else if(username.length < 3){
          return 'Username short';
        }

        return null;
  };

  //password validator possible structure
  passwordValidator(String password){
        if(password.isEmpty){
          return 'Password empty';
        }else if(password.length < 3){
          return 'PasswordShort';
        }
        return null;
  }  



 //new build function
Widget _buildInputFields(
    String label,
    TextEditingController textController,
    TextInputType textInputType,
    IconData icon,
    Color iconColor,
    String Function(String) validator
  ) {
    return Container(
        margin: EdgeInsets.only(left: 20, bottom: 20),
        child: Container(
          padding: EdgeInsets.only(right: 20),
          child: Row(
            children: <Widget>[
              Flexible(
                child: TextFormField(
                  controller: textController,
                  validator: validator,
                  style: new TextStyle(color: Colors.white),
                  keyboardType: textInputType,
                  decoration: InputDecoration(
                      labelText: label,
                      fillColor: Colors.white,
                      labelStyle: TextStyle(
                          color: Colors.white, fontWeight: FontWeight.w600),
                      enabledBorder: OutlineInputBorder(
                        borderSide:
                            const BorderSide(color: Colors.white30, width: 2.0),
                        borderRadius: BorderRadius.circular(25.0),
                      ),
                      suffixIcon: IconButton(
                        icon: Icon(icon, color: iconColor),
                        onPressed: () {},
                      )),
                ),
              ),
            ],
          ),
        ));
  }

    //calling your function
   _buildInputFields(label, textController, textInputType, icon, iconColor, usernameValidator);
   _buildInputFields(label, textController, textInputType, icon, iconColor, passwordValidator);

nonybrighto answer is perfectly right, but after adding null check updated code is

// Function to create form field
Widget createFormField(String label, TextEditingController controller,
  String? Function(String?)? validator) {
return TextFormField(
  decoration: InputDecoration(labelText: label),
  controller: controller,
  autovalidate: true,
  validator: validator,
);
}

// Validator
String? Function(String?)? idValidator = (String? value) {
if (value!.isEmpty) {
  return 'Id Must be entered';
} else {
  return int.tryParse(value) == null ? 'Id Must be number' : null;
}
 };

// Finally
createFormField('Id', idController, idValidator),

As you are already using a validator, I guess you only need to pass it as parameter in the _buildInputFields , right?

It would be something like that:

Widget _buildInputFields(
...
    Color iconColor,
    Function validator,
  ) {
...
                child: TextFormField(
                  controller: textController,
                  validator: validator,
                  style: new TextStyle(color: Colors.white),
...
  }

You can use that and you'll be pretty much fine.

However, you can be even more specific and use the validator Function type, like that:

Widget _buildInputFields(
...
    Color iconColor,
    FormFieldValidator<String> validator,
...

So you could define the validator as methods of your State class and reuse them, or just specify them directly, in the _buildInputFields call.

In the example below, you have one field, Name, which uses the _notEmptyValidator, a method defined in the same class. As LastName follows the same logic, it reuses this method.

...
 String _notEmptyValidator(String value) {
   if (value.isEmpty) {
     return 'Please enter some text';
   }
 }
...
 Column(
  children: <Widget>[ 
    _buildInputFields("Name", _notEmptyValidator),
    _buildInputFields("Last Name", _notEmptyValidator),
text" : null),
  ]
...

In the example below, I'm keeping previous fields, but I'm adding a new one. This new field have a very specific validation logic, I'll define the validation method in the _buildInputFields call, thus not reusing it in other fields.

...
 Column(
  children: <Widget>[ 
    _buildInputFields("Name", _notEmptyValidator),
    _buildInputFields("Last Name", _notEmptyValidator),
text" : null),
    _buildInputFields("Valid Number", (value) {
      if (double.tryParse(value) == null) {
        return "Please input a valid number";
      }
    },
  ]
...

You can also create a inner function in validator if you need to send more than just the value to your method. I needed that in order to implement internalization in validators.

TextFormField(
  // The validator receives the text that the user has entered.
  validator: (value) {
    return myMethod(value, context, ...);
  },
  //... other attributes
)

For Flutter 2

Custom Widget Function

CupertinoTextFormFieldRow customTextField(
    String pretext, String supportText, Function(String) validatorFun) {
  return CupertinoTextFormFieldRow(
    prefix: Text(pretext),
    placeholder: supportText,
    validator: (val) => validatorFun(val!),
  );
}

Define validator functions

acceptNonNull(String value) {
  if (value.trim().isEmpty) {
    return 'Please enter a value';
  }
  return null;
}
checkPassword(String value) {
  if (value.isEmpty) {
    return 'Password empty';
  } else if (value.length < 8) {
    return 'Password too weak';
  } //accept only if string contains both alphabests and numerics
    else if (!value.contains(RegExp(r'^[a-zA-Z0-9]+$'))) {
    return 'Password should contain aplpha numeric characters';
  }
  return null;
}

Build your Widgets

customTextField("First Name", "Enter Your First Name Here",acceptNonNull),
customTextField("Last Name", "Enter Your Last Name Here", acceptNonNull),
customTextField("Password", "Choose a Password", checkPassword)

Just a simple example, using nullsafety, flutter 2, getx

Login_Screen

  validator: (value) {
     return AuthController.instance.emailValidator(AuthController.instance.emailController.text);
 },

Auth_Controller

emailValidator(String email){
    if ((!email.contains('@')) ||
      (email.trim().length < 8))
    {
      return 'Invalid email';
    }
    //validado com sucesso
    return null;
  }

for the new update with null safety you should use that because if you use the verified answer it will give you an error .

    //username validator possible structure
   Function(String?) usernameValidator = (String? username){
        if(username!.isEmpty){
          return 'Username empty';
        }else if(username!.length < 3){
          return 'Username short';
        }

        return null;
  };

  //password validator possible structure
  passwordValidator(String? password){
        if(password!.isEmpty){
          return 'Password empty';
        }else if(password!.length < 3){
          return 'PasswordShort';
        }
        return null;
  }  



 //new build function
Widget _buildInputFields(
    String label,
    TextEditingController textController,
    TextInputType textInputType,
    IconData icon,
    Color iconColor,
    String? Function(String?) validator
  ) {
    return Container(
        margin: EdgeInsets.only(left: 20, bottom: 20),
        child: Container(
          padding: EdgeInsets.only(right: 20),
          child: Row(
            children: <Widget>[
              Flexible(
                child: TextFormField(
                  controller: textController,
                  validator: validator,
                  style: new TextStyle(color: Colors.white),
                  keyboardType: textInputType,
                  decoration: InputDecoration(
                      labelText: label,
                      fillColor: Colors.white,
                      labelStyle: TextStyle(
                          color: Colors.white, fontWeight: FontWeight.w600),
                      enabledBorder: OutlineInputBorder(
                        borderSide:
                            const BorderSide(color: Colors.white30, width: 2.0),
                        borderRadius: BorderRadius.circular(25.0),
                      ),
                      suffixIcon: IconButton(
                        icon: Icon(icon, color: iconColor),
                        onPressed: () {},
                      )),
                ),
              ),
            ],
          ),
        ));
  }

    //calling your function
   _buildInputFields(label, textController, textInputType, icon, iconColor, usernameValidator);
   _buildInputFields(label, textController, textInputType, icon, iconColor, passwordValidator);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM