Handle changes to a text field
In some cases, it's useful to run a callback function every time the text in a text field changes. For example, you might want to build a search screen with autocomplete functionality where you want to update the results as the user types.
How do you run a callback function every time the text changes? With Flutter, you have two options:
- Supply an
onChanged()
callback to aTextField
or aTextFormField
. - Use a
TextEditingController
.
1. Supply an onChanged()
callback to a TextField
or a TextFormField
#The simplest approach is to supply an onChanged()
callback to a TextField
or a TextFormField
. Whenever the text changes, the callback is invoked.
In this example, print the current value and length of the text field to the console every time the text changes.
It's important to use characters when dealing with user input, as text may contain complex characters. This ensures that every character is counted correctly as they appear to the user.
TextField(
onChanged: (text) {
print('First text field: $text (${text.characters.length})');
},
),
2. Use a TextEditingController
#A more powerful, but more elaborate approach, is to supply a TextEditingController
as the controller
property of the TextField
or a TextFormField
.
To be notified when the text changes, listen to the controller using the addListener()
method using the following steps:
- Create a
TextEditingController
. - Connect the
TextEditingController
to a text field. - Create a function to print the latest value.
- Listen to the controller for changes.
Create a TextEditingController
#Create a TextEditingController
:
// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
const MyCustomForm({super.key});
@override
State<MyCustomForm> createState() => _MyCustomFormState();
}
// Define a corresponding State class.
// This class holds data related to the Form.
class _MyCustomFormState extends State<MyCustomForm> {
// Create a text controller. Later, use it to retrieve the
// current value of the TextField.
final myController = TextEditingController();
@override
void dispose() {
// Clean up the controller when the widget is removed from the
// widget tree.
myController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// Fill this out in the next step.
}
}
Connect the TextEditingController
to a text field
#Supply the TextEditingController
to either a TextField
or a TextFormField
. Once you wire these two classes together, you can begin listening for changes to the text field.
TextField(
controller: myController,
),
Create a function to print the latest value
#You need a function to run every time the text changes. Create a method in the _MyCustomFormState
class that prints out the current value of the text field.
void _printLatestValue() {
final text = myController.text;
print('Second text field: $text (${text.characters.length})');
}
Listen to the controller for changes
#Finally, listen to the TextEditingController
and call the _printLatestValue()
method when the text changes. Use the addListener()
method for this purpose.
Begin listening for changes when the _MyCustomFormState
class is initialized, and stop listening when the _MyCustomFormState
is disposed.
@override
void initState() {
super.initState();
// Start listening to changes.
myController.addListener(_printLatestValue);
}
@override
void dispose() {
// Clean up the controller when the widget is removed from the widget tree.
// This also removes the _printLatestValue listener.
myController.dispose();
super.dispose();
}
Interactive example
#import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Retrieve Text Input',
home: MyCustomForm(),
);
}
}
// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
const MyCustomForm({super.key});
@override
State<MyCustomForm> createState() => _MyCustomFormState();
}
// Define a corresponding State class.
// This class holds data related to the Form.
class _MyCustomFormState extends State<MyCustomForm> {
// Create a text controller and use it to retrieve the current value
// of the TextField.
final myController = TextEditingController();
@override
void initState() {
super.initState();
// Start listening to changes.
myController.addListener(_printLatestValue);
}
@override
void dispose() {
// Clean up the controller when the widget is removed from the widget tree.
// This also removes the _printLatestValue listener.
myController.dispose();
super.dispose();
}
void _printLatestValue() {
final text = myController.text;
print('Second text field: $text (${text.characters.length})');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Retrieve Text Input'),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
TextField(
onChanged: (text) {
print('First text field: $text (${text.characters.length})');
},
),
TextField(
controller: myController,
),
],
),
),
);
}
}
Unless stated otherwise, the documentation on this site reflects the latest stable version of Flutter. Page last updated on 2024-06-26. View source or report an issue.