Flutter TextFormField结合Firestore验证无提示问题求助
解决TextFormField异步Firestore验证不生效的问题
我创建了一个TextFormField并希望对其进行验证,验证逻辑为:从Firestore数据库查询输入值,若该值已存在则返回提示信息,否则返回null。但目前输入值后,即便值已存在也未出现任何提示,请求帮助。
class GenerateUID extends StatefulWidget { final String idAreadyExistsString; final String noSPacesAllowedString; final String fieldCannotBeEmptyString; const GenerateUID( {super.key, required this.idAreadyExistsString, required this.noSPacesAllowedString, required this.fieldCannotBeEmptyString}); @override State<GenerateUID> createState() => _GenerateUIDState(); } class _GenerateUIDState extends State<GenerateUID> { TextEditingController employeeIDController = TextEditingController(); final GlobalKey<FormState> _formkey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Form( key: _formkey, child: TextFormField( inputFormatters: [ FilteringTextInputFormatter.allow(RegExp("[0-9]")), LengthLimitingTextInputFormatter(10) ], controller: employeeIDController, style: const TextStyle( color: Colors.black, fontWeight: FontWeight.bold, fontSize: 20), onChanged: (value) { _formkey.currentState?.validate(); }, validator: (value) { FirebaseFirestore.instance .collection("ADMIN IDS") .where("ID", isEqualTo: value) .get() .then((valuess) { if (valuess.docs.isNotEmpty) { return widget.idAreadyExistsString; } }); if (value!.contains(" ")) { return (widget.noSPacesAllowedString); } if (value.isEmpty) { return (widget.fieldCannotBeEmptyString); } return null; }, ), )), ); } }
问题原因
Flutter的validator是同步回调函数,而你在里面用了Firestore的异步查询(get()+then())。异步操作还没完成,validator就已经执行到末尾的return null了,导致查询到ID存在时,错误信息根本传不回来。
解决方法
既然validator不支持异步逻辑,我们可以手动用状态变量管理异步验证的结果,再结合同步验证逻辑:
修改后的代码
class GenerateUID extends StatefulWidget { final String idAreadyExistsString; final String noSPacesAllowedString; final String fieldCannotBeEmptyString; const GenerateUID( {super.key, required this.idAreadyExistsString, required this.noSPacesAllowedString, required this.fieldCannotBeEmptyString}); @override State<GenerateUID> createState() => _GenerateUIDState(); } class _GenerateUIDState extends State<GenerateUID> { TextEditingController employeeIDController = TextEditingController(); final GlobalKey<FormState> _formkey = GlobalKey<FormState>(); // 新增状态变量,存储异步验证的错误信息 String? _asyncError; @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Form( key: _formkey, // 开启用户交互时自动验证,实时更新提示 autovalidateMode: AutovalidateMode.onUserInteraction, child: TextFormField( inputFormatters: [ FilteringTextInputFormatter.allow(RegExp("[0-9]")), LengthLimitingTextInputFormatter(10) ], controller: employeeIDController, style: const TextStyle( color: Colors.black, fontWeight: FontWeight.bold, fontSize: 20), onChanged: (value) async { // 每次输入先清空之前的异步错误 setState(() => _asyncError = null); // 先做同步验证,不通过就不用查数据库了 if (value.contains(" ") || value.isEmpty) { _formkey.currentState?.validate(); return; } // 异步查询Firestore final snapshot = await FirebaseFirestore.instance .collection("ADMIN IDS") .where("ID", isEqualTo: value) .get(); // 根据查询结果更新错误状态 setState(() { _asyncError = snapshot.docs.isNotEmpty ? widget.idAreadyExistsString : null; }); // 触发验证更新UI _formkey.currentState?.validate(); }, validator: (value) { // 优先返回异步验证的错误 if (_asyncError != null) { return _asyncError; } // 原有的同步验证逻辑 if (value!.contains(" ")) { return widget.noSPacesAllowedString; } if (value.isEmpty) { return widget.fieldCannotBeEmptyString; } return null; }, ), )), ); } }
关键改动说明
- 新增
_asyncError状态变量,专门存储Firestore查询返回的错误信息 - 在
onChanged里先做同步验证,通过后再发起异步查询,避免无效的数据库请求 - 查询完成后用
setState更新错误状态,再触发validate()刷新UI validator优先检查异步错误,再执行同步验证逻辑
内容的提问来源于stack exchange,提问作者Eben Oasis
相关产品推荐
相关产品推荐

