alertTextFieldDidChange(_:, for: .editingChanged)

I have an alertController, with one textField.. and alertAction button [Save].

When the textField presented (empty), the [Save].isEnabled = false. If user type anything in textField (none space), button [Save].isEnabled = true.

code:

field.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: .editingChanged)

validation code:

var alertController : UIAlertController?
@objc func alertTextFieldDidChange(_ sender: UITextField) {
   alertController?.actions[0].isEnabled = sender.text!.trimmingCharacters(in: .whitespacesAndNewlines).count > 0
    }

[Save] button works as expected. However, when I insert text in textField (as default entry):

textField.text = "Test" 

textField showing "Text", if user choose to accept the default value "Test", [Save] button isEnabled will not change. User will have to type something in textField.

I need some direction .. Thanks.

Answered by Scott in 713894022

Why do you enter a default text and not a placeholder ?

Placeholder isn’t the right choice for proposing text that the user may choose to accept without further editing; it should be used as a hint to help the user know what to enter. For example, if saving a new document the default (proposed) name could be Untitled and the placeholder could be Enter a name. The placeholder would appear only if the user erases the proposed name.

And here’s a tip on enabling the button to match the text. If you reuse the text change handler for .editingDidBegin like this:

textField.addTarget(self, action: #selector(self.alertTextFieldDidChange), for: .editingDidBegin)
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange), for: .editingChanged)

...then it will get called just before the alert appears, but after the needed alert?.actions array is set up. So now your enable/disable logic can be in just one place.

Anyone? or, maybe I post the question at wrong place?

You should show the complete code for the alert.

Why do you enter a default text and not a placeholder ?

               textField.placeholder = "your text"

Here is an example:

     var alert : UIAlertController?

    @objc func alertTextFieldDidChange(_ sender: UITextField) {
       alert?.actions[0].isEnabled = sender.text!.count > 0
    }

     @IBAction func testAlert(_ sender: Any) {  // let's call the alert in an IBAction

          //1. Create the alert controller.
          alert = UIAlertController(title: "Test", message: "Type something ", preferredStyle: .alert)
          
          //2. Add the text field.
          alert?.addTextField(configurationHandler: { (textField) -> Void in
               textField.placeholder = "your text"
               textField.keyboardType = UIKeyboardType.emailAddress // if you need @ sign
               // alertTextFieldDidChange enable Save button
               textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(_:)), for: UIControl.Event.editingChanged)
          })
          
          //3. Grab the value from the text field.
          let yesAction = UIAlertAction(title: "Save", style: .default, handler: { (action) -> Void in
               let textField = self.alert?.textFields![0] 
               if textField?.text! == "" {
                    print("empty")  // should never occur !
               } else {
                    print("not empty", textField?.text! ?? "")
               }

          yesAction.isEnabled = false        // at start
          alert?.addAction(yesAction)
          
          let cancelAction = UIAlertAction(title: "Annuler", style: .default, handler: nil)
          alert?.addAction(cancelAction)

          // 4. Present the alert.
          self.present(alert!, animated: true, completion: { print("Presented") })
}

If you want button activated if field not empty, change as:

          yesAction.isEnabled = self.alert?.textFields![0].text! != "" // false

OK, just do it. So implement the code I mentioned:

          yesAction.isEnabled = self.alert?.textFields![0].text! != "" 

and replace

               textField.placeholder = "your text"

with

               textField.text = "default text"
Accepted Answer

Why do you enter a default text and not a placeholder ?

Placeholder isn’t the right choice for proposing text that the user may choose to accept without further editing; it should be used as a hint to help the user know what to enter. For example, if saving a new document the default (proposed) name could be Untitled and the placeholder could be Enter a name. The placeholder would appear only if the user erases the proposed name.

And here’s a tip on enabling the button to match the text. If you reuse the text change handler for .editingDidBegin like this:

textField.addTarget(self, action: #selector(self.alertTextFieldDidChange), for: .editingDidBegin)
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange), for: .editingChanged)

...then it will get called just before the alert appears, but after the needed alert?.actions array is set up. So now your enable/disable logic can be in just one place.

alertTextFieldDidChange(_:, for: .editingChanged)
 
 
Q