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
CodePudding user response:
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')
],
),
);
}
CodePudding user response:
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();
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();
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
CodePudding user response:
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')
],
));
}
}