2
votes

I'm new in Flutter and I am following this official example about text fields: https://flutter.dev/docs/cookbook/forms/text-field-changes

There is an axample for listen to changes in the controller of a text field widget. Please note this fragment of code _MyCustomFormState

final myController = TextEditingController();

@override
void initState() {
  super.initState();
  myController.addListener(_printLatestValue);
}

_printLatestValue() {
  print("Second text field: ${myController.text}");
}

If I have two fields and two controllers, I would like to have just one listener, and display some message depending on which controller called the method. I would like to do something like this:

final myController1 = TextEditingController();
final myController2 = TextEditingController();

@override
void initState() {
  super.initState();
  myController1.addListener(_printLatestValue('message1'));
  myController1.addListener(_printLatestValue('message2'));
}

_printLatestValue(message) {
  print("Second text field: ${myController.text + message}");
}

which is not possible because the method addListener() uses some called VoidCallback, which have no arguments. At least that is what I understood from the Flutter docs.

So, if it is possible, how can I achieve what I'm looking for?

1
What is your question? still unclear. - satish

1 Answers

2
votes

You're almost correct, but not quite. You're free to pass in any arguments to the listener. However, those arguments need to come from somewhere else - TextEditingController does not supply any, and it does not expect any return values. In other words, the signature should be something like: () => listener(...).

So to answer your question, you're free to do something like the following to distinguish the controllers:

  void initState() {
    super.initState();
    firstController.addListener(() => _printLatestValue('first'));
    secondController.addListener(() => _printLatestValue('second'));
  }

Full working example:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Text controllers',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final firstController = TextEditingController();
  final secondController = TextEditingController();


  void initState() {
    super.initState();
    firstController.addListener(() => _printLatestValue('first'));
    secondController.addListener(() => _printLatestValue('second'));
  }

  @override
  void dispose() {
    firstController.dispose();
    secondController.dispose();
    super.dispose();
  }

  _printLatestValue(message) {
    if (message == 'first') {
      print('Received form first controller: ${firstController.text}');
    } else {
      print('Received from second controller: ${secondController.text}');
    }
  }

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Controllers', style: TextStyle(fontSize: 18)),
        ),
        body: Center(
          child: Column(
            children: <Widget>[
              TextField(controller: firstController,),
              TextField(controller: secondController,)
            ],
          ),
        ),
    );
  }
}

Note that in this case, listener will only print the text from a TextField that was changed.