new TextFormField(
validator: (value) async{
if (value.isEmpty) {
return 'Username is required.';
}
if (await checkUser()) {
return 'Username is already taken.';
}
},
controller: userNameController,
decoration: InputDecoration(hintText: 'Username'),
),
我有一个供用户使用的表单,我想检查用户在Firestore的日期数据库中是否已经存在。
Future checkUser() async {
var user = await Firestore.instance
.collection('users')
.document(userNameController.text)
.get();
return user.exists;
}
这是我检查用户文档是否已存在于数据库中的功能。 但是验证器给了我这个错误。
[dart]无法将参数类型“(字符串)→未来”分配给参数类型“(字符串)→字符串”。
我应该如何解决此问题?
答案 0 :(得分:4)
目前,我认为您无法将unshield.exe
与Future
关联起来。
您可以做的是通过单击按钮或以其他方式验证数据,然后在验证程序响应变量上设置状态。
validator
答案 1 :(得分:1)
答案 2 :(得分:0)
下面的示例只是一个草图,您应该创建用于检查案例登录和状态管理的函数。 但简而言之-您可以将TextFormField中的数据传递给函数,并以任何方式同时验证它们。
import 'package:flutter/material.dart';
void main() => runApp(ScratchApp());
class ScratchApp extends StatefulWidget {
@override
_ScratchAppState createState() => _ScratchAppState();
}
class _ScratchAppState extends State<ScratchApp> {
bool _validLogin;
bool _isLoading;
String _loginError;
String _login;
final _formKey = GlobalKey<FormState>();
final TextEditingController _loginInputController = TextEditingController();
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
child: TextFormField(
keyboardType: TextInputType.phone,
validator: _validateLogin,
onSaved: (value) => _login = value,
onFieldSubmitted: (value) => _login = value,
controller: _loginInputController,
),
),
Container(
child: RaisedButton(
onPressed: () async {
_formKey.currentState?.validate();
if (_formKey.currentState.validate()) {
setState(() {
// start your Circularprogress indicator
_isLoading = true;
});
_formKey.currentState.save();
// function that checks, for example, Firebase login
_validLogin = await verifyLogin(_login);
if (_validLogin)
Navigator.pushNamed(context, goSomeWhereInYourApp);
}
},
child: Text('Login'),
),
),
],
);
}
String _validateLogin(loginVal) {
if (loginVal.isEmpty) {
return 'Empty login';
} else if (loginVal.length < 3) {
return 'Login too short';
}
if (!_validLogin) {
_validLogin = true;
setState(() {
_isLoading = false;
});
return _loginError;
}
return null;
}
@override
void dispose() {
super.dispose();
}
}
答案 3 :(得分:0)
我最近需要执行此操作以进行用户名验证(以检查Firebase中是否已存在用户名),这就是我如何在TextFormField上实现异步验证(不安装任何其他程序包)。我有一个“用户”集合,其中文档名称是唯一的用户名(Firebase集合中不能有重复的文档名称,但要注意区分大小写)
//In my state class
class _MyFormState extends State<MyForm> {
final _usernameFormFieldKey = GlobalKey<FormFieldState>();
//Create a focus node
FocusNode _usernameFocusNode;
//Create a controller
final TextEditingController _usernameController = new TextEditingController();
bool _isUsernameTaken = false;
String _usernameErrorString;
@override
void initState() {
super.initState();
_usernameFocusNode = FocusNode();
//set up focus node listeners
_usernameFocusNode.addListener(_onUsernameFocusChange);
}
@override
void dispose() {
_usernameFocusNode.dispose();
_usernameController.dispose();
super.dispose();
}
}
然后在我的TextFormField小部件中
TextFormField(
keyboardType: TextInputType.text,
focusNode: _usernameFocusNode,
textInputAction: TextInputAction.next,
controller: _usernameController,
key: _usernameFormFieldKey,
onEditingComplete: _usernameEditingComplete,
validator: (value) => _isUsernameTaken ? "Username already taken" : _usernameErrorString,)
在小部件上失去焦点时监听焦点变化。您也可以为“ onEditingComplete”方法做类似的事情
void _onUsernameFocusChange() {
if (!_usernameFocusNode.hasFocus) {
String message = UsernameValidator.validate(_usernameController.text.trim());
//First make sure username is in valid format, if it is then check firebase
if (message == null) {
Firestore.instance.collection("my_users").document(_usernameController.text.trim()).get().then((doc) {
if (doc.exists) {
setState(() {
_isUsernameTaken = true;
_usernameErrorString = null;
});
} else {
setState(() {
_isUsernameTaken = false;
_usernameErrorString = null;
});
}
_usernameFormFieldKey.currentState.validate();
}).catchError((onError) {
setState(() {
_isUsernameTaken = false;
_usernameErrorString = "Having trouble verifying username. Please try again";
});
_usernameFormFieldKey.currentState.validate();
});
} else {
setState(() {
_usernameErrorString = message;
});
_usernameFormFieldKey.currentState.validate();
}
}
}
为完整性起见,这是我的用户名验证器类
class UsernameValidator {
static String validate(String value) {
final regexUsername = RegExp(r"^[a-zA-Z0-9_]{3,20}$");
String trimmedValue = value.trim();
if (trimmedValue.isEmpty) {
return "Username can't be empty";
}
if (trimmedValue.length < 3) {
return "Username min is 3 characters";
}
if (!regexUsername.hasMatch(trimmedValue)) {
return "Usernames should be a maximum of 20 characters with letters, numbers or underscores only. Thanks!";
}
return null;
}
}
答案 4 :(得分:0)
在使用Firebase的实时数据库时,我遇到了同样的问题,但是我发现了一个非常不错的解决方案,类似于Zroq的解决方案。此函数创建一个简单的弹出表单,以使用户输入名称。本质上,我试图查看特定用户的特定名称是否已经在数据库中,如果为true,则显示验证错误。我创建了一个名为“ duplicate”的局部变量,只要用户单击“确定”按钮即可完成更改。然后,如果有错误,我可以再次调用验证器,验证器将显示它。
void add(BuildContext context, String email) {
String _name;
bool duplicate = false;
showDialog(
context: context,
builder: (_) {
final key = GlobalKey<FormState>();
return GestureDetector(
onTap: () => FocusScope.of(context).requestFocus(new FocusNode()),
child: AlertDialog(
title: Text("Add a Workspace"),
content: Form(
key: key,
child: TextFormField(
autocorrect: true,
autofocus: false,
decoration: const InputDecoration(
labelText: 'Title',
),
enableInteractiveSelection: true,
textCapitalization: TextCapitalization.sentences,
onSaved: (value) => _name = value.trim(),
validator: (value) {
final validCharacters =
RegExp(r'^[a-zA-Z0-9]+( [a-zA-Z0-9]+)*$');
if (!validCharacters.hasMatch(value.trim())) {
return 'Alphanumeric characters only.';
} else if (duplicate) {
return 'Workspace already exists for this user';
}
return null;
},
),
),
actions: <Widget>[
FlatButton(
child: const Text("Ok"),
onPressed: () async {
duplicate = false;
if (key.currentState.validate()) {
key.currentState.save();
if (await addToDatabase(_name, email) == false) {
duplicate = true;
key.currentState.validate();
} else {
Navigator.of(context).pop(true);
}
}
},
),
FlatButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop(false);
},
),
],
),
);
});
}