How to pass a validator to the `TextFormField'

2019-06-13 06:03发布

问题:

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 ?

回答1:

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);


回答2:

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";
      }
    },
  ]
...