I am new on RiverPod. I want to get input from user bıt I couldn't use a TextField in my app with RiverPod.TextController's value is empty.
Also I got an error FormatError:Invalid Number
final User_value = StateProvider<int>((ref) {
return 0;
});
final controller = TextEditingController();
final controllerprovider = StateProvider<String>((ref) {
return controller.text;
});
class HomePage extends ConsumerWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final controllertext = ref.watch(controllerprovider);
final user_value = ref.watch(User_value);
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Home"),
],
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: Text("Go to the Counter page"),
onPressed: () {
Navigator.of(context).push(
//Navigation
MaterialPageRoute(builder: (((context) => CounterPage()))),
);
},
),
SizedBox(
height: 60,
),
TextField(
controller: controller,
decoration: InputDecoration(
labelText: "Enter a number",
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.numbers),
suffixIcon: controllertext.isEmpty
? Container(
width: 0,
)
: IconButton(
icon: Icon(Icons.close), //If user wants to enter another number this is the easy way to delete the current one.
onPressed: () {
ref.invalidate(controllerprovider);
},
)),
),
IconButton(
onPressed: () {
temp = ref.read(User_value.notifier).state;
print(controllertext);
ref.read(User_value.notifier).state =
int.parse(ref.read(controllerprovider.notifier).state); // Thats where I got the error.
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("Input has been saved"),
action: SnackBarAction(
label: "Undo",
onPressed: () {
ref.read(User_value.notifier).state = temp;
},
),
));
},
icon: Icon(Icons.add_task)),
],
));
}
}
I couldn't solve how to get input from user.User should be enter a number,click the button and the number should be saved as controller's state.
CodePudding user response:
It is better to use int.tryParse
and provide a default value on exceptions, you dont need to use global TextEditingController. You can follow this widget.
final userValueProvider = StateProvider<int>((ref) {
return 0;
});
final controllerProvider = StateProvider<String>((ref) {
return "";
});
class HomePage extends ConsumerWidget {
HomePage({Key? key}) : super(key: key);
final controller = TextEditingController();
@override
Widget build(BuildContext context, WidgetRef ref) {
final controllerText = ref.watch(controllerProvider);
final userValue = ref.watch(userValueProvider);
debugPrint("rebuilding");
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("controllerText $controllerText userValue $userValue"),
TextField(
controller: controller,
onChanged: (value) {
debugPrint(value);
ref.read(controllerProvider.notifier).state = value;
},
decoration: InputDecoration(
labelText: "Enter a number",
suffixIcon: controllerText.isEmpty
? null
: IconButton(
icon: const Icon(Icons.close),
onPressed: () {
ref.read(controllerProvider.notifier).state = ""; //prefer using .update
controller.clear(); //clear TextField
},
)),
),
IconButton(
onPressed: () {
final oldValue = ref.read(userValueProvider.notifier).state;
ref
.read(userValueProvider.notifier)
.update((state) => int.tryParse(controller.text) ?? 0);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text("Input has been saved"),
action: SnackBarAction(
label: "Undo",
onPressed: () {
ref
.read(userValueProvider.notifier)
.update((state) => oldValue);
},
),
));
},
icon: const Icon(Icons.add_task)),
],
),
);
}
}