Search code examples
iosswiftuitextfielduialertcontroller

How do you disable a UIAlertAction depending on a UITextField in a UIAlertController?


I'm using a UIAlertController to present the user with a dialog to enter a 5-digit CRN. I want the Add button to be disabled until there are five and only five digits in the UITextField.

Here's what the UI looks like:

A UIAlertController with a text field and two actions. The text field has seven digits entered into it, but the Add button is still disabled.

Here are the properties that are set up for the UIAlertController:

var alertController: UIAlertController!

var addAlertAction: UIAlertAction! {
    return UIAlertAction(title: "Add", style: .default)
}

Here's how I'm initializing them in the viewDidLoad method:

self.alertController = UIAlertController(title: "Add Class", message: "Input CRN", preferredStyle: .alert)
self.alertController.addAction(addAlertAction)
self.alertController.addAction(UIAlertAction(title: "Cancel", style: .destructive))
self.alertController.addTextField { (textField) in
    textField.delegate = self
    textField.keyboardType = .numberPad
}

Here's how I'm trying to disable/enable the button using the UITextFieldDelegate method:

func textFieldDidEndEditing(_ textField: UITextField) {
    if ((textField.text?.characters.count)! == 5) {
        self.alertController.actions[0].isEnabled = true
    } else {
        self.alertController.actions[0].isEnabled = false
    }
}

However, the button remains disabled (or enabled) all the time. It never gets enabled. What's going wrong?


Solution

  • Implement the logic in the shouldChangeCharactersIn delegate method of UITextField. This method gets fired on change in each character of textfield. You can build the logic taking the range parameter into consideration.

    Here is the code that works perfectly.

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        
        if ((range.location == 4 && range.length == 0) || (range.location == 5 && range.length == 1)) {
            self.alertController.actions[0].isEnabled = true
        }else{
            self.alertController.actions[0].isEnabled = false
        }
    
        return true;
    }
    

    Tested successfully in Swift 3, XCode 8 and iOS 10

    Hope that helps. Happy coding ...