5

I'm new to Flutter and Firebase and I am trying to validate user input from a form and run it up against a the firebase collection.

I ask users to create a username and want to validate that there is not an existing username in my Firebase directory.

I got this validation method from the discussion on Check if Field Already exists in Flutter Firestore. I want to feed the method a name, build a List of documents with that name, and confirm that none exist.

  Future<bool> doesNameAlreadyExist(String name) async {
    final QuerySnapshot result = await Firestore.instance
        .collection('user')
        .where('user_id', isEqualTo: name)
        .limit(1)
        .getDocuments();
    final List<DocumentSnapshot> documents = result.documents;
    return documents.length == 1;
  }

I hope to be able to call this method within the validator of the text form field as I have done below.

new TextFormField(
          decoration: new InputDecoration(labelText: 'Username'),
          validator: (value) => doesNameAlreadyExist(value) ? "Username already taken" : null,
          onSaved: (value) => _username = value,
        ),

However, this throws an error that I must have a static type of bool for the validator.

My question: how can I (1) create a static boolean method that would be able to search Firebase or (2) how can I get the same functionality with the async call (ideally, without having to build another widget)?

dshukertjr
  • 15,244
  • 11
  • 57
  • 94
PJQuakJag
  • 1,067
  • 4
  • 16
  • 35

2 Answers2

4

Future give then() Method, you can use That. You can modify your validator Method as:

validator: (value) => checkUserValue(value) ? "Username already taken" : null,


  bool _userExist = false;
  checkUserValue<bool>(String user) {
    _doesEmailAlreadyExist(user).then((val){
      if(val){
        print ("UserName Already Exits");
        _userExist = val;
      }
      else{
        print ("UserName is Available");
        _userExist = val;
      }
    });
    return _userExist;
  }
anmol.majhail
  • 48,256
  • 14
  • 136
  • 105
  • Thanks Anmol for the quick response. I kept the Future method and added the checkUserValue method (put it right below the Future constructor). Unfortunately, it's not properly calling on the Firebase database (I already have it configured and pulling data from other collections so I don't think that is the issue). Also, I'm getting the following error: "Dart Error: Unhandled exception: Failed assertion: boolean expression must not be null". Any idea why this may not be calling Firebase correctly or where the boolean expression is not getting evaluated? – PJQuakJag Oct 01 '18 at 14:54
  • Thanks so much @Anmol. It's correctly recognizing the user and passing correctly. However, the validator is not triggering. Any idea of how to get this to work? Can the validator work when being called with the future? – PJQuakJag Oct 02 '18 at 00:58
  • I tried it, It do get triggered & error is shown- Make sure you define function & variable outside Build Override. It also get triggered on keyboard Submit button. – anmol.majhail Oct 02 '18 at 07:02
  • Confirmed, both are outside the build. I also have an email and password field where I have validation to confirm that both fields exist. Those work fine (not doing any database look up, just confirming user has entered text). When I enter data to test and leave the email blank with an identical username, the email validator error does not trigger initially. However, if I try to submit it again, it will trigger. Any idea what could be happen? – PJQuakJag Oct 02 '18 at 14:20
  • Best would be here to Manually trigger Validator using FormState Global key. formkey.currentState.validate() will trigger the Validator & return true & false. – anmol.majhail Oct 02 '18 at 15:07
  • Actually, found my error was that I had an extra parentheses hidden causing the booleans to pass incorrectly. Appreciate all your help on this one! – PJQuakJag Oct 03 '18 at 02:21
3

Old question but found that the current answer wasn't working for me, as since the doesNameAlreadyExist(user) function returns a future, then the value of _userExist will return prior to evaluating the then() callback.

I found suggestions elsewhere to use the onChanged event to track and update the status of the async validation you need to do, then check that in the validator handler which has to be a synchronous function. So something like this:

// somewhere above the build function
bool _nameAlreadyExists = false;
bool _autoValidate = false;
Future<void> setNameExists(String name) async {
    bool _nameAlreadyExists = await yourAsyncFunctionForDoingTheCheckHere(name);
}

// inside your build function when defining the Form
Form(
    key: _formKey,
    autovalidateMode: _autoValidate ? AutovalidateMode.onUserInteraction : AutovalidateMode.disabled, ...

// your TextFormField
TextFormField(
    validator: (value) => (value == null || value.isEmpty ? "Name is required"
                  : (_nameAlreadyExists ? "Name already in use." : null)),
    onChanged: (txt) => setNameExists(txt), ...

David Ferraro
  • 55
  • 1
  • 6