0

I have a Flutter app with a "Create Account" form that has a field for Username. Upon entering a username and hitting the "Submit" button, my validator functions run for the form. I would like to query my Firestore database and ensure that the username entered isn't already taken.

My validator (in the Username form):

validator: (value) {
  Future<bool> usernameTaken = uniqueCheck(value);
  if (usernameTaken) {
    return 'Username is already taken!';
  } else {
    return null;
  }

My uniqueCheck function:

  Future<bool> uniqueCheck(String? value) async {
    bool alreadyTaken = false;
    var snapshot = await FirebaseFirestore.instance
      .collection('users')
      .where('username', isEqualTo: value)
      .get();
    snapshot.docs.forEach((result) {
      alreadyTaken = true;
    });
    return alreadyTaken;
  }

The trouble is my validator finishes before my uniqueCheck function can return with the proper result (such as if the username is taken and usernameTaken is true. I thought await would fix this, but apparently not.

What am I doing wrong here?

2 Answers 2

1

Try this:

validator: (value) async {
  Future<bool> usernameTaken = await uniqueCheck(value);
  if (usernameTaken) {
    return 'Username is already taken!';
  } else {
    return null;
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

I don't think validators can be async since they return a String and not Futures. (per this thread: stackoverflow.com/questions/55360628/…, and also the massive amount of red text I get when I try adding async to the validator) But solid thinking! I thought the same thing regarding async/await because I really just want this to truly "wait" for the Firestore query to return.
0

SOLUTION: I figured it out. Validators can't be async so the solution was to call the uniqueCheck function in the onPressed function of the Submit button. I could then properly await to see if the email was taken and then I called setState(){} to redraw the screen.

onPressed: () async {
      emailTaken = await uniqueCheck(emailKey.currentState!.value);
      setState(() {});
      if (formKey.currentState!.validate()) {
        formKey.currentState?.save();
        // {... add to database ...}
        // {... navigate to successful sign-in screen ...}
      }
    },

Note that the emailTaken bool is global to this scope so that when setState(){} is called, the validator in the email field will pick it up as true.

Email field form validator function:

validator: (value) {
      if ((value!.isEmpty) | !(value.contains('@'))) {
        return 'Please enter a valid email address.';
      } else if (emailTaken) {
        return 'Email is already taken!';
      } else {
        return null;
      }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.