Can anyone tell me how to validate UITextFields
inside of a UIAlertController
?
I need it to prevent the user from clicking \"Save\" unless
Register for the text field change notifications and validate the text fields there:
//...
alert.addTextFieldWithConfigurationHandler {
(textFieldEmail: UITextField!) in
textFieldEmail.placeholder = "Enter valid email adress"
textFieldEmail.keyboardType = .EmailAddress
}
let textFieldValidationObserver: (NSNotification!) -> Void = { _ in
let textFieldName = alert.textFields![0] as! UITextField
let textFieldEmail = alert.textFields![1] as! UITextField
saveAction.enabled = self.isValidEmail(textFieldEmail.text) && textFieldName.text.length > 0
}
// Notifications for textFieldName changes
NSNotificationCenter.defaultCenter().addObserverForName(UITextFieldTextDidChangeNotification,
object: alert.textFields![0], // textFieldName
queue: NSOperationQueue.mainQueue(), usingBlock: textFieldValidationObserver)
// Notifications for textFieldEmail changes
NSNotificationCenter.defaultCenter().addObserverForName(UITextFieldTextDidChangeNotification,
object: alert.textFields![1], // textFieldEmail
queue: NSOperationQueue.mainQueue(), usingBlock: textFieldValidationObserver)
alert.addAction(saveAction)
//...
Following what @Kupendiran presented for email input validation with UIAlertController. Here is a version thats working with Objective-C and the newer UIAlertController format as UIAlertView is now depreciated.
Step 1. add the following to .h and .m files with other properties and variables
.h
@property(strong,nonatomic)UITextField *emailAddressField;
.m
UITextField *emailAddressField;
Step 2. Create the alert message, buttons and validation process.
UIAlertController * alertView = [UIAlertController
alertControllerWithTitle:@"E-Mail Address"
message:@"Enter your email address:"
preferredStyle:UIAlertControllerStyleAlert];
[alertView addTextFieldWithConfigurationHandler:^(UITextField *emailTextField) {
emailTextField.placeholder = @"E-Mail Address";
emailTextField.autocorrectionType= UITextAutocorrectionTypeYes;
emailTextField.keyboardType= UIKeyboardTypeEmailAddress;
emailAddressField = emailTextField;
}];
Step 3. Create the alert actions
UIAlertAction * ok= [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
//Handel your OK button action here
NSLog(@"Email Address Entered is: %@", emailAddressField.text);
//Validate email address is correct format
if(emailAddressField.text.length>0){//
NSString *emailString= emailAddressField.text;
NSString *emailReg= @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSPredicate *emailTest= [NSPredicate predicateWithFormat:@"SELF MATCHES %@",emailReg];
if(([emailTest evaluateWithObject:emailString]!=YES) || [emailString isEqualToString:@""]){
NSLog(@"Email Address Entered is not valid: %@", emailAddressField.text);
UIAlertController *badEmailAlert = [UIAlertController
alertControllerWithTitle:@"Email Address"
message:@"\nPlease enter valid Email (example@example.com format) ."
preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:badEmailAlert animated:YES completion:nil];
UIAlertAction* cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[badEmailAlert dismissViewControllerAnimated:YES completion:nil];
[self presentViewController:alertView animated:YES completion:nil];
}];
[badEmailAlert addAction:cancel];
}else{
NSLog(@"your TextField successfully validated");
}
}else{
[self presentViewController:alertView animated:YES completion:nil];
}
}];
[alertView addAction:ok];
//Handel your Cancel button action here
UIAlertAction* cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[alertView dismissViewControllerAnimated:YES completion:nil];
}];
[alertView addAction:cancel];
Step 4. Present the alert message on the screen
[self presentViewController:alertView animated:YES completion:nil];
This can be done by extending UIAlertViewController
:
extension UIAlertController {
func isValidEmail(_ email: String) -> Bool {
return email.characters.count > 0 && NSPredicate(format: "self matches %@", "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,64}").evaluate(with: email)
}
func isValidPassword(_ password: String) -> Bool {
return password.characters.count > 4 && password.rangeOfCharacter(from: .whitespacesAndNewlines) == nil
}
func textDidChangeInLoginAlert() {
if let email = textFields?[0].text,
let password = textFields?[1].text,
let action = actions.last {
action.isEnabled = isValidEmail(email) && isValidPassword(password)
}
}
}
// ViewController
override func viewDidLoad() {
super.viewDidLoad()
let alert = UIAlertController(title: "Please Log In", message: nil, preferredStyle: .alert)
alert.addTextField {
$0.placeholder = "Email"
$0.addTarget(alert, action: #selector(alert.textDidChangeInLoginAlert), for: .editingChanged)
}
alert.addTextField {
$0.placeholder = "Password"
$0.isSecureTextEntry = true
$0.addTarget(alert, action: #selector(alert. textDidChangeInLoginAlert), for: .editingChanged)
}
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
let loginAction = UIAlertAction(title: "Submit", style: .default) { [unowned self] _ in
guard let email = alert.textFields?[0].text,
let password = alert.textFields?[1].text
else { return } // Should never happen
// Perform login action
}
loginAction.isEnabled = false
alert.addAction(loginAction)
present(alert, animated: true)
}
Most elegant way is to use
NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextFieldTextDidChange...
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
let saveAction = UIAlertAction(title:"Save", style: .destructive, handler: { (action) -> Void in
})
alert.addAction(saveAction)
alert.addTextField(configurationHandler: { (textField) in
textField.placeholder = "Enter something"
NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextFieldTextDidChange, object: textField, queue: OperationQueue.main) { (notification) in
saveAction.isEnabled = textField.text!.length > 0
}
})
present(alert, animated: true, completion: nil)
For Swift 4.2 (NSNotification.Name.UITextFieldTextDidChange) update:
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
let saveAction = UIAlertAction(title:"Save", style: .destructive, handler: { (action) -> Void in
})
alert.addAction(saveAction)
alert.addTextField(configurationHandler: { (textField) in
textField.placeholder = "Enter something"
NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: textField, queue: OperationQueue.main) { (notification) in
saveAction.isEnabled = textField.text?.count > 0
}
})
present(alert, animated: true, completion: nil)
Swift 4.0 Example
This is based on Mihael Isaev's answer. I had to change it up a bit to get the Save button to NOT be active immediately. I tried with and without the placeholder text. In the end, had to specifically inactivate Save to start with. In my case, I elected to use an alert title rather than placeholder text. But, it worked the same either way.
let alert = UIAlertController(title: "Enter Username", message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) -> Void in}))
let saveAction = UIAlertAction(title:"Save", style: .destructive, handler: { (action) -> Void in
})
alert.addAction(saveAction)
alert.addTextField(configurationHandler: { (textField) in
textField.text = ""
saveAction.isEnabled = false
NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextFieldTextDidChange, object: textField, queue: OperationQueue.main) { (notification) in
saveAction.isEnabled = textField.text!.length > 0
}
})
self.present(alert, animated: true, completion: nil)