'How to update a form after a field is changed
I've got a form and I want to re-do a calculation when the user finishes editing any of the fields. I thought onFieldSubmitted would do it but this never gets called. In the minimal example below I want the recalc() function to be called when the user moves off the field. I know onChange will work but I don't want the recalculation to be done every time the user enters a character as it is a bit slow and it's irritating, in my opinion, to see validation errors while still composing the fields contents.
I'm using Flutter 2.10.4 with the "Edge (web-javascript)" device.
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: 'Flutter Demo',
      home: MyHomePage(title: 'Form demo'),
    );
  }
}
class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: const Center(child: MyForm()),
    );
  }
}
class MyForm extends StatefulWidget {
  const MyForm({Key? key}) : super(key: key);
  @override
  State<MyForm> createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
  int _q = 0;
  void recalc() {
    print("Recalculate");
    setState(() {
      _q += 1;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Form(
        child: Column(
      children: [
        TextFormField(
          onFieldSubmitted: (value) {
            recalc();
          },
        ),
        TextFormField(
          onFieldSubmitted: (value) {
            recalc();
          },
        ),
        Text('changed $_q')
      ],
    ));
  }
}
EDIT: I realise now that onFieldSubmitted gets fired if I press ENTER on a field, not when I tab away from it. I'm using the web-javascript device on a PC so I do have an ENTER key - not sure how this would work if I were using the Android emulator
Solution 1:[1]
if I understand it correctly you need a focusNode for that
first step create focusNode
FocusNode focusNode = FocusNode();
TextEditingController firstController = TextEditingController();
second step send to textformfield
   TextFormField(
      focusNode: focusNode,
      controller: firstController,
    ),
and addlistener in initstate
 void initState() {
     focusNode.addListener(() {
      if(!focusNode.hasFocus){
        print(firstController.text); 
        recalc();
      }
    });
    super.initState();
  }
Dont forget dispose
  @override
  void dispose() {
  
     focusNode.dispose();
     firstController.dispose();
    super.dispose();
  }
Full code:
import 'package:flutter/material.dart';
import 'package:googleapis/storage/v1.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: 'Flutter Demo',
      home: MyHomePage(title: 'Form demo'),
    );
  }
}
class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: const Center(child: MyForm()),
    );
  }
}
class MyForm extends StatefulWidget {
  const MyForm({Key? key}) : super(key: key);
  @override
  State<MyForm> createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
  int _q = 0;
  void recalc() {
    print("Recalculate");
    setState(() {
      _q += 1;
    });
  }
  //TODO: create focusnode and textcontroller 
  FocusNode focusNode = FocusNode();
  TextEditingController firstController = TextEditingController();
  @override
  void initState() {
  //TODO: create a listener
     focusNode.addListener(() {
      if(!focusNode.hasFocus){
        //TODO: You can write any function
       //TODO: you can take the text
        print(firstController.text); 
        recalc();
      }
    });
    super.initState();
  }
  @override
  void dispose() {
    // TODO: Dont forget to dispose
     focusNode.dispose();
     firstController.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Form(
        child: Column(
      children: [
        TextFormField(
          focusNode: focusNode,
          controller: firstController,
         
        ),
        TextFormField(
         //You can do for here
        ),
        Text('changed $_q')
      ],
    ));
  }
}
hopefully it benefits
Solution 2:[2]
You need a TextEditingController to controll value of TextField. see more details at this post.
In case you want to detect user unfocus the field without submit, u can use FocusNode to take control of them
final controller1 = TextEditingController(text: defaultValue);
final controller2 = TextEditingController(text: defaultValue);
int _q = 0;
void recalc() {
  print("Recalculate");
  setState(() {
    _q += 1;
  });
  controller1.text = defaultValue;
  controller2.text = defaultValue;
}
@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Column(
      children: [
        TextFormField(
          controller: controller1,
          onFieldSubmitted: (value) {
            recalc();
          },
        ),
        TextFormField(
          controller: controller2,
          onFieldSubmitted: (value) {
            recalc();
          },
        ),
        Text('changed $_q')
      ],
    ),
  );
}
    					Solution 3:[3]
You Can try this way there is no other way the user can to other textfield it seems!!
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: 'Flutter Demo',
      home: MyHomePage(title: 'Form demo'),
    );
  }
}
class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: const Center(child: MyForm()),
    );
  }
}
class MyForm extends StatefulWidget {
  const MyForm({Key? key}) : super(key: key);
  @override
  State<MyForm> createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
  int _q = 0;
  void recalc() {
    print("Recalculate");
    setState(() {
      _q += 1;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Form(
        child: Column(
          children: [
            TextFormField(
              onEditingComplete: ( ){
                recalc();
              },
            ),
            TextFormField(
              onEditingComplete: ( ){
                recalc();
              },
            ),
            Text('changed $_q')
          ],
        ));
  }
}
    					Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | 
