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