ios - ¿Cómo validar TextFields en un UIAlertController?
swift uitextfield (10)
Esto se puede hacer extendiendo 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)
}
¿Alguien puede decirme cómo validar los UITextFields
de UIAlertController
UITextFields
dentro de un UIAlertController
?
Lo necesito para evitar que el usuario haga clic en "Guardar" a menos que se ingresen ambos campos.
Aquí está mi código hasta ahora:
@IBAction func btnStart(sender: AnyObject) {
var alert = UIAlertController(title: "New user",
message: "Add a new user",
preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Save",
style: .Default) { (action: UIAlertAction!) -> Void in
self.textFieldName = alert.textFields![0] as UITextField
self.textFieldEmail = alert.textFields![1] as UITextField
self.saveUser(self.textFieldName.text, email: self.textFieldEmail.text)
self.tableView.reloadData()
}
saveAction.enabled = false
let cancelAction = UIAlertAction(title: "Cancel",
style: .Default) { (action: UIAlertAction!) -> Void in
}
alert.addTextFieldWithConfigurationHandler {
(textFieldName: UITextField!) in
textFieldName.placeholder = "Enter full name"
}
alert.addTextFieldWithConfigurationHandler {
(textFieldEmail: UITextField!) in
textFieldEmail.placeholder = "Enter valid email adress"
textFieldEmail.keyboardType = .EmailAddress
}
alert.addAction(saveAction)
alert.addAction(cancelAction)
presentViewController(alert,
animated: true,
completion: nil)
}
Esta es mi función para validar el campo de correo electrónico:
func isValidEmail(testStr:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+//.[A-Za-z]{2,4}"
if let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx) {
return emailTest.evaluateWithObject(testStr)
}
return false
}
Esto se puede lograr a través de NSNotificationCenter antes de mostrar el controlador de alerta; todo lo que tiene que hacer es pedirle al centro de notificaciones que observe la notificación de UITextFieldTextDidChangeNotification y debería estar en buen estado,
A continuación se detalla la implementación de la misma.
@IBAction func showAlert(sender: AnyObject) {
var alert = UIAlertController(title: "New user",
message: "Add a new user",
preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Save",
style: .Default) { (action: UIAlertAction!) -> Void in
println("do your stuff here")
}
saveAction.enabled = false
let cancelAction = UIAlertAction(title: "Cancel",
style: .Default) { (action: UIAlertAction!) -> Void in
}
alert.addTextFieldWithConfigurationHandler {
(textFieldName: UITextField!) in
textFieldName.placeholder = "Enter full name"
}
alert.addTextFieldWithConfigurationHandler {
(textFieldEmail: UITextField!) in
textFieldEmail.placeholder = "Enter valid email adress"
textFieldEmail.keyboardType = .EmailAddress
}
// adding the notification observer here
NSNotificationCenter.defaultCenter().addObserverForName(UITextFieldTextDidChangeNotification, object:alert.textFields?[0],
queue: NSOperationQueue.mainQueue()) { (notification) -> Void in
let textFieldName = alert.textFields?[0] as! UITextField
let textFieldEmail = alert.textFields![1] as! UITextField
saveAction.enabled = self.isValidEmail(textFieldEmail.text) && !textFieldName.text.isEmpty
}
NSNotificationCenter.defaultCenter().addObserverForName(UITextFieldTextDidChangeNotification, object:alert.textFields?[1],
queue: NSOperationQueue.mainQueue()) { (notification) -> Void in
let textFieldEmail = alert.textFields?[1] as! UITextField
let textFieldName = alert.textFields?[0] as! UITextField
saveAction.enabled = self.isValidEmail(textFieldEmail.text) && !textFieldName.text.isEmpty
}
alert.addAction(saveAction)
alert.addAction(cancelAction)
presentViewController(alert,
animated: true,
completion: nil)
}
// email validation code method
func isValidEmail(testStr:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+//.[A-Za-z]{2,4}"
if let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx) as NSPredicate? {
return emailTest.evaluateWithObject(testStr)
}
return false
}
Implementé una subclase UIAlertController que le permite agregar un controlador en los cambios de campo de texto cuando lo agrega a la alerta:
public class TextEnabledAlertController: UIAlertController {
private var textFieldActions = [UITextField: ((UITextField)->Void)]()
func addTextField(configurationHandler: ((UITextField) -> Void)? = nil, textChangeAction:((UITextField)->Void)?) {
super.addTextField(configurationHandler: { (textField) in
configurationHandler?(textField)
if let textChangeAction = textChangeAction {
self.textFieldActions[textField] = textChangeAction
textField.addTarget(self, action: #selector(self.textFieldChanged), for: .editingChanged)
}
})
}
@objc private func textFieldChanged(sender: UITextField) {
if let textChangeAction = textFieldActions[sender] {
textChangeAction(sender)
}
}
}
Entonces, para su caso, lo único que debe agregarse es llamar a la función isValidEmail en el controlador textChangeAction:
alert.addTextField(configurationHandler: { (textField) in
// things you want to configure on the textfield
}) { (textField) in
saveAction.isEnabled = isValidEmail(textField.text ?? "")
}
La forma más elegante es usar
NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextFieldTextDidChange...
Ejemplo de Swift 3.0
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)
Primero, necesitas agregar algunas variables a tu clase:
private weak var saveAction : UIAlertAction?
private weak var textFieldName : UITextField?
private weak var textFieldEmail : UITextField?
private var validName = false
private var validEmail = false
Luego, cuando desee configurar el controlador de alerta (solo pegué las cosas que deben cambiarse):
alert.addTextFieldWithConfigurationHandler {
(textFieldName: UITextField!) in
textFieldName.placeholder = "Enter full name"
textFieldName.delegate = self
self.textFieldName = textFieldName
}
alert.addTextFieldWithConfigurationHandler {
(textFieldEmail: UITextField!) in
textFieldEmail.placeholder = "Enter valid email adress"
textFieldEmail.keyboardType = .EmailAddress
textFieldEmail.delegate = self
self.textFieldEmail = textFieldEmail
}
let saveAction = UIAlertAction(title: "Save",
style: .Default) { (action: UIAlertAction!) -> Void in
// here you are sure the name and email are correct
let name = (alert.textFields[0] as! UITextField).text
let email = (alert.textFields[1] as! UITextField).text
}
saveAction.enabled = false
self.saveAction = saveAction
Finalmente, deberías implementar este método de delegado:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let newText = NSString(string: textField.text).stringByReplacingCharactersInRange(range, withString: string)
if textField == self.textFieldName {
// validate newText for the name requirements
validName = self.validateName(newText)
} else if textField == self.textFieldEmail {
// validate newText for the email requirements
validEmail = self.validateEmail(newText)
}
self.saveAction?.enabled = validEmail && validName
return true
}
Puede usar el siguiente código para validar TextFields en un UIAlertController: -
Paso 1:
Declare "email_TF" to your viewcontroller.h
for example:
@property(strong,nonatomic)UITextField *email_TF;
Paso 2:
UIAlertController *alert= [UIAlertController alertControllerWithTitle:@"Forgot Password?" message:nil preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler: ^(UITextField *textField){
textField.placeholder= @"Enter Your Valid Email";
textField.autocorrectionType= UITextAutocorrectionTypeYes;
textField.keyboardType= UIKeyboardTypeEmailAddress;
email_TF= textField;
}];
Paso 3:
UIAlertAction *noButton= [UIAlertAction actionWithTitle:@"No, thanks" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action){
//Handel no, thanks button
}];
[alert addAction:noButton];
UIAlertAction *yesButton= [UIAlertAction actionWithTitle:@"Yes, please" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
//Handel your yes please button action here
NSLog(@"%@", email_TF.text);
if(email_TF.text.length>0){//
NSString *emailString= email_TF.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:@""]){
UIAlertView *loginalert= [[UIAlertView alloc] initWithTitle:@"Forgot Password !" message:@"/nPlease enter valid Email ([email protected] format) ." delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[loginalert show];
}else{
NSLog(@"your TextField successfully validated");
}
}else{
UIAlertView *alert= [[UIAlertView alloc] initWithTitle:@"Forgot Password !" message:@"/nPlease Enter Your Email..." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
}
}];
[alert addAction:yesButton];
Etapa 4:
[self presentViewController:alert animated:YES completion:nil];
Regístrese para recibir notificaciones de cambio de campo de texto y valide los campos de texto allí
//...
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)
//...
Siguiendo lo que @Kupendiran presentó para la validación de entrada de correo electrónico con UIAlertController. Aquí hay una versión que funciona con Objective-C y el nuevo formato UIAlertController como UIAlertView ahora está depreciado.
Paso 1. agregue lo siguiente a los archivos .h y .m con otras propiedades y variables
.h
@property(strong,nonatomic)UITextField *emailAddressField;
.metro
UITextField *emailAddressField;
Paso 2. Crea el mensaje de alerta, botones y proceso de validación.
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;
}];
Paso 3. Crea las acciones de alerta.
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 ([email protected] 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];
Paso 4. Presentar el mensaje de alerta en la pantalla.
[self presentViewController:alertView animated:YES completion:nil];
Para la actualización Swift 4.2 (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: UITextField.textDidChangeNotification, object: textField, queue: OperationQueue.main) { (notification) in
saveAction.isEnabled = textField.text?.count > 0
}
})
present(alert, animated: true, completion: nil)
Swift 4.0 Ejemplo
Esto se basa en la respuesta de Mihael Isaev. Tuve que cambiarlo un poco para que el botón Guardar NO se active inmediatamente. Intenté con y sin el texto del marcador de posición. Al final, tuve que desactivar específicamente Guardar para comenzar. En mi caso, elegí usar un título de alerta en lugar del texto de marcador de posición. Pero, funcionó igual de cualquier manera.
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)