Chris
Chris

Reputation: 2274

Check if username is in Firestore Database while editing UITextField

I am trying to check wether or not a username is taken while the user types in the name. Currently I have these two functions that are working almost the way I would want it to work but not 100% correctly:

textFieldDidChange:

 @objc private func textFieldDidChange(_ textField: UITextField) {

    switch textField {

    // ... //    
    case usernameTextField:
        if textField.text?.isEmpty == false {
            checkUsername(field: textField.text!) { (success) in
                print(textField.text!)
                if success == true {
                    // username is taken
                    print("Username is taken")
                    self.setupUsernameTextField()
                    self.checkUsernameImage.image = UIImage(named: "false")
                    self.checkUserNameLabel.text = "Benutzername ist bereits vergeben"
                } else {
                    // username is not taken
                    print("Username is not taken")
                    self.checkUsernameImage.image = UIImage(named: "correct")
                    self.checkUserNameLabel.text = "gültiger Benutzername"
                }
            }
        }else {
            self.checkUsernameImage.image = UIImage(named: "false")
            self.checkUserNameLabel.text = "kein gültiger Benutzername"
        }
    default:
        break
    }

}


// helper function to check if username is in databse -> later in Datahandler
func checkUsername(field: String, completion: @escaping (Bool) -> Void) {

    let db = Firestore.firestore()
    let collectionRef = db.collection("users")
    collectionRef.whereField("username", isEqualTo: field).getDocuments { (snapshot, err) in
        if let err = err {
            print("Error getting document: \(err)")
        } else if (snapshot?.isEmpty)! {
            completion(false)
        } else {
            for document in (snapshot?.documents)! {
                if document.data()["username"] != nil {
                    completion(true)
                }
            }
        }
    }
}

Problem: If you type in something quite fast or if your internet connection isn't very good it displays Username is not taken when it actually is.

If you look at the Instagram-App, they are doing it the perfect way:

  1. type something in, even fast
  2. after you stop typing for maybe a second, a loading indicator pops up and only then u get feedback wether or not the username is taken
  3. type something in while loading indicator is active, it stops and only starts again if you stop typing again.

My Question: How do I realize that??? Like how do I know when the user "stops" typing but the textField is still editing ? I tried it with shouldEndEditing but that only works if the textfield is no longer selected and thats not what I would like to achieve. In the end I would like to have the exact same process as in the Instagram app.

Any ideas on how to realize that??

Upvotes: 0

Views: 84

Answers (1)

Chris
Chris

Reputation: 2274

With @Jays suggestion I was able to make it work:

My textField is connected with a didChange method which looks like this:

timer.invalidate() // reset timer

// start the timer
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)

And the connected timerAction-method looks like this:

// called every time interval from the timer
@objc func timerAction() {
    checkUsername(field: usernameTextField.text!) { (success) in
        print(self.usernameTextField.text!)
        if success == true {
            // username is taken
            print("Username is taken")
            self.setupUsernameTextField()
            self.checkUsernameImage.image = UIImage(named: "false")
            self.checkUserNameLabel.text = "Benutzername ist bereits vergeben"
            // stop timer
            self.timer.invalidate()
        } else {
            // username is not taken
            print("Username is not taken")
            // stop timer
            self.timer.invalidate()
        }
    }
}

Works exactly the way I want it to work, thanks for the help:)

Upvotes: 1

Related Questions