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
.
onChanged()
callback to a TextField
or a TextFormField
1. Supply an 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 of the text field to the console every time the text changes.
TextField( onChanged: (text) { print('First text field: $text'); }, ),
TextEditingController
2. Use a 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.
TextEditingController
Create a Create a TextEditingController
:
// Define a custom Form widget. class MyCustomForm extends StatefulWidget { const MyCustomForm({Key? key}) : super(key: key); @override _MyCustomFormState 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. } }
TextEditingController
to a text field
Connect the 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() { print('Second text field: ${myController.text}'); }
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({Key? key}) : super(key: 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({Key? key}) : super(key: key);
@override
_MyCustomFormState 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() {
print('Second text field: ${myController.text}');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Retrieve Text Input'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
onChanged: (text) {
print('First text field: $text');
},
),
TextField(
controller: myController,
),
],
),
),
);
}
}