Flutter异步验证表单

10
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数据库中。

Translated text:

我有一个用户表单,想要检查该用户是否已经存在于Firestore数据库中。

Future checkUser() async {
var user = await Firestore.instance
    .collection('users')
    .document(userNameController.text)
    .get();
return user.exists;

这是我的函数,用于检查用户文档是否已存在于数据库中。但验证器给了我这个错误。

[dart] 参数类型'(String) → Future'无法分配给参数类型'(String) → String'。

我该如何解决这个问题?


我给他们写了一个问题,面临着同样的事情。 https://github.com/flutter/flutter/issues/18884 - Chris
以下是一个执行异步表单验证的示例: [![带有模态进度指示器的异步表单验证](https://i.stack.imgur.com/QVaqw.gif)](https://i.stack.imgur.com/QVaqw.gif)您可以在此处找到源代码: https://github.com/mmcc007/modal_progress_hud/tree/master/example - mmccabe
3个回答

21

目前无法将Future验证器(validator)关联起来。

您可以在单击按钮或其他方式上验证数据,并将状态设置为验证器响应变量。

 @override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
    body: Form(
        key: _formKey,
        child: Column(children: [
          new TextFormField(
              validator: (value) {
                return usernameValidator;
              },
              decoration: InputDecoration(hintText: 'Username')),
          RaisedButton(
            onPressed: () async {
              var response = await checkUser();

              setState(() {
                this.usernameValidator = response;
              });

              if (_formKey.currentState.validate()) {}
            },
            child: Text('Submit'),
          )
        ])));
}

1
我正在尝试让这个工作起来,但我的情况略有不同,因为我需要将验证器的“value”传递给负责函数。在这种情况下,“usernameValidator”是什么,当我需要将“value”传递给等待函数时,我该如何使这种情况起作用。 - supersize

1

最近我需要进行用户名验证(检查Firebase中是否已存在用户名),这就是我如何在TextFormField上实现异步验证的方法(无需安装任何额外的软件包)。我有一个“users”集合,其中文档名称是唯一的用户名(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;
  }
}

1
我在使用Firebase的实时数据库时遇到了同样的问题,但我找到了一个类似于Zroq解决方案的相当不错的解决方法。此函数创建一个简单的弹出表单,以让用户输入名称。本质上,我试图查看特定用户的特定名称是否已经存在于数据库中,并在为真时显示验证错误。我创建了一个名为“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);
              },
            ),
          ],
        ),
      );
    });
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接