I am trying to take the details of the address , the problem i am facing is after i click the button where _formchecked
is set to true the autovalidate is working only for one TextFormField at a time , Why the autovalidate not working simultaneously on all the textformfield
class AddAddress extends StatefulWidget {
const AddAddress({super.key});
@override
State<AddAddress> createState() => _AddAddressState();
}
class _AddAddressState extends State<AddAddress> {
final _fullNameKey = GlobalKey<FormState>();
final _phoneNumberKey = GlobalKey<FormState>();
final _houseNumberKey = GlobalKey<FormState>();
final _roadNameKey = GlobalKey<FormState>();
final _cityNameKey = GlobalKey<FormState>();
TextEditingController? fullNameController;
TextEditingController? phoneNumberController;
TextEditingController? houseNumberController;
TextEditingController? roadNameController;
TextEditingController? cityNameController;
bool _formChecked = false;
bool checkedValue = false;
final List<bool> _isSelected = [true, false];
@override
void initState() {
fullNameController = TextEditingController();
phoneNumberController = TextEditingController();
houseNumberController = TextEditingController();
roadNameController = TextEditingController();
cityNameController = TextEditingController();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: "Add New Address".appBarText(),
leading: const Icon(Icons.navigate_before),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Form(
key: _fullNameKey,
child: TextFormField(
controller: fullNameController,
autovalidateMode: _formChecked
? AutovalidateMode.always
: AutovalidateMode.disabled,
validator: (value) {
if (value == null || fullNameController?.text.trim() == "") {
return "Name cannot be empty";
}
if (value.length < 3) {
return "Username must be greater than 3 characters";
}
return null;
},
decoration: InputDecoration(
labelText: "Full Name",
labelStyle: textStyleMediumRegular()),
),
),
Form(
key: _phoneNumberKey,
child: TextFormField(
keyboardType: TextInputType.phone,
controller: phoneNumberController,
autovalidateMode: _formChecked
? AutovalidateMode.always
: AutovalidateMode.disabled,
validator: (value) {
if (value == null ||
phoneNumberController?.text.trim() == "") {
return "Phone Number cannot be empty";
}
if (value.length < 10 || value.length > 13) {
return "Invalid Phone Number";
}
return null;
},
decoration: const InputDecoration(labelText: "Phone Number"),
),
),
Form(
key: _houseNumberKey,
child: TextFormField(
controller: houseNumberController,
autovalidateMode: _formChecked
? AutovalidateMode.always
: AutovalidateMode.disabled,
validator: (value) {
if (value == null ||
houseNumberController?.text.trim() == "") {
return "This field cannot be empty";
}
return null;
},
decoration: const InputDecoration(
labelText: "House Name, Building Number"),
),
),
Form(
key: _roadNameKey,
child: TextFormField(
controller: roadNameController,
autovalidateMode: _formChecked
? AutovalidateMode.always
: AutovalidateMode.disabled,
validator: (value) {
if (value == null || roadNameController?.text.trim() == "") {
return "This field cannot be empty";
}
return null;
},
decoration:
const InputDecoration(labelText: "Road Name, Area, Colony"),
),
),
Form(
key: _cityNameKey,
child: TextFormField(
controller: cityNameController,
autovalidateMode: _formChecked
? AutovalidateMode.always
: AutovalidateMode.disabled,
validator: (value) {
if (value == null || cityNameController?.text.trim() == "") {
return "This field cannot be empty";
}
return null;
},
decoration: const InputDecoration(labelText: "City"),
),
),
)),
bottomNavigationBar: FilledButton(
onPressed: () {
if (_fullNameKey.currentState!.validate() &&
_phoneNumberKey.currentState!.validate() &&
_cityNameKey.currentState!.validate() &&
_houseNumberKey.currentState!.validate() &&
_roadNameKey.currentState!.validate()) {
print("Helllllllllllllllllllloo");
// Here create the model and add
setState(() {
_formChecked = true;
});
}
},
child: Text("Save Address"),
);
}
}
CodePudding user response:
Move setState
out of if
branch. It is only called when all forms are valid.
onPressed: () {
if (_fullNameKey.currentState!.validate() &&
_phoneNumberKey.currentState!.validate() &&
_cityNameKey.currentState!.validate() &&
_houseNumberKey.currentState!.validate() &&
_roadNameKey.currentState!.validate()) {
print("Helllllllllllllllllllloo");
// Here create the model and add
}
setState(() {
_formChecked = true;
});
},
CodePudding user response:
It seems you are also using _formChecked
to avoid the error messages right at the time of app launch.
The problem is that at app launch since _formChecked
is false
, the autovalidateMode
is set to disabled
and when you encounter an invalid entry, _formChecked
remains false
, thereby not resetting the values of autovalidateMode
until all fields are validated.
To fix this:
- Firstly, you need to keep
autovalidateMode
set toalways
for all fields. - Secondly,
setState
should be called each time the save button is pressed so that validation results are reset. - Thirdly, a new bool variable needs to be introduced that would contain the result of validation. Its value would be used to decide whether the data needs to be added or not.
- Last but not the least,
_formChecked
will now be used solely for the purpose of checking whether the form has been checked at least for the first time or not. Its value will be updated totrue
on the first form check. In order to avoid the error messages at the app launch, all code inside the validator function needs to be executed only if_formChecked
istrue
.
Here is the revised code:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: "Add New Address".appBarText(),
leading: const Icon(Icons.navigate_before),
),
body: SingleChildScrollView(
child:
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Form(
key: _fullNameKey,
child: TextFormField(
controller: fullNameController,
autovalidateMode: AutovalidateMode.always,
validator: (value) {
if (_formChecked) {
if (value == null || fullNameController?.text.trim() == "") {
return "Name cannot be empty";
}
if (value.length < 3) {
return "Username must be greater than 3 characters";
}
return null;
}
},
decoration: InputDecoration(
labelText: "Full Name",
labelStyle: textStyleMediumRegular(),
),
),
),
Form(
key: _phoneNumberKey,
child: TextFormField(
keyboardType: TextInputType.phone,
controller: phoneNumberController,
autovalidateMode: AutovalidateMode.always,
validator: (value) {
if (_formChecked) {
if (value == null || phoneNumberController?.text.trim() == "") {
return "Phone Number cannot be empty";
}
if (value.length < 10 || value.length > 13) {
return "Invalid Phone Number";
}
return null;
}
},
decoration: const InputDecoration(labelText: "Phone Number"),
),
),
Form(
key: _houseNumberKey,
child: TextFormField(
controller: houseNumberController,
autovalidateMode: AutovalidateMode.always,
validator: (value) {
if (_formChecked) {
if (value == null || houseNumberController?.text.trim() == "") {
return "This field cannot be empty";
}
return null;
}
},
decoration:
const InputDecoration(labelText: "House Name, Building Number"),
),
),
Form(
key: _roadNameKey,
child: TextFormField(
controller: roadNameController,
autovalidateMode: AutovalidateMode.always,
validator: (value) {
if (_formChecked) {
if (value == null || roadNameController?.text.trim() == "") {
return "This field cannot be empty";
}
return null;
}
},
decoration:
const InputDecoration(labelText: "Road Name, Area, Colony"),
),
),
Form(
key: _cityNameKey,
child: TextFormField(
controller: cityNameController,
autovalidateMode: AutovalidateMode.always,
validator: (value) {
if (_formChecked) {
if (value == null || cityNameController?.text.trim() == "") {
return "This field cannot be empty";
}
return null;
}
},
decoration: const InputDecoration(labelText: "City"),
),
),
])),
bottomNavigationBar: MaterialButton(
onPressed: () {
if (_formChecked == false) _formChecked = true;
bool isValidated;
if (_fullNameKey.currentState!.validate() &&
_phoneNumberKey.currentState!.validate() &&
_cityNameKey.currentState!.validate() &&
_houseNumberKey.currentState!.validate() &&
_roadNameKey.currentState!.validate()) {
print("Helllllllllllllllllllloo");
isValidated = true;
} else {
isValidated = false;
}
setState(() {
if (isValidated) {
// Here create the model and add
}
});
},
child: Text("Save Address"),
),
);
}
Hope it helps!