I have a username textfield, a password textfield and a button. When one of these fields are empty, the button should be disabled (onPressed null). When both of these fields contains text, the button should be enabled (onPressed not null). A very basic usecase, which I cannot find a solution for.
ValueListenableBuilder only works for a single TextEditingController, and Listenable.merge cannot be uses on multiple TextEditingController´s either. I read another solution where you could wrap multiple ValueListenableBuilders into another widget, and then use this widget. But this seems to "complex" for me for such a simple problem, and this is not a nice scaleable solution. I´ve tried creating a getter:
get loginButtonEnabled {
if (_usernameController.text != '' && _passwordController.text != '' && !loading) {
return true;
}
return false;
}
then use it on the button:
ElevatedButton.icon(
onPressed: loginButtonEnabled ? loginClicked : null,
label: Text('Login'),
),
and when onChanged fired on my textfields, they would call setState()
to update the ui.
Problem with this is, that when the user types in some text, the textfield loses focus for some reason. And furthermore, this is not an elegant solution either.
So is there a more suitable approach to this common usecase?
CodePudding user response:
You can follow this snippet, I am listening both controller. You might use StatefulWidget, for that overrideinitState and dispose state
class LogForm extends StatelessWidget {
const LogForm({super.key});
@override
Widget build(BuildContext context) {
final ValueNotifier<bool> isEnabled = ValueNotifier(false);
late final TextEditingController passController;
late final TextEditingController nameController;
nameController = TextEditingController()
..addListener(() {
if (passController.text.isNotEmpty && nameController.text.isNotEmpty) {
isEnabled.value = true;
} else {
isEnabled.value = false;
}
});
passController = TextEditingController()
..addListener(() {
if (passController.text.isNotEmpty && nameController.text.isNotEmpty) {
isEnabled.value = true;
} else {
isEnabled.value = false;
}
});
return Column(
children: [
TextFormField(
controller: nameController,
),
TextFormField(
controller: passController,
),
ValueListenableBuilder<bool>(
valueListenable: isEnabled,
builder: (context, value, child) {
return ElevatedButton(
onPressed: value ? () {} : null, child: Text("Btn"));
},
)
],
);
}
}