Related
I am adding a UITextField to a UIAlertController, which appears as an AlertView. Before dismissing the UIAlertController, I want to validate the input of the UITextField. Based on the validation I want to dismiss the UIAlertController or not. But I have no clue how to prevent the dismissing action of the UIAlertController when a button is pressed. Has anyone solved this problem or any ideas where to start ? I went to google but no luck :/ Thanks!
You're correct: if the user can tap a button in your alert, the alert will be dismissed. So you want to prevent the user from tapping the button! It's all just a matter of disabling your UIAlertAction buttons. If an alert action is disabled, the user can't tap it to dismiss.
To combine this with text field validation, use a text field delegate method or action method (configured in the text field's configuration handler when you create it) to enable/disable the UIAlertActions appropriately depending on what text has (or hasn't) been entered.
Here's an example. We created the text field like this:
alert.addTextFieldWithConfigurationHandler {
(tf:UITextField!) in
tf.addTarget(self, action: "textChanged:", forControlEvents: .EditingChanged)
}
We have a Cancel action and an OK action, and we brought the OK action into the world disabled:
(alert.actions[1] as UIAlertAction).enabled = false
Subsequently, the user can't tap OK unless there is some actual text in the text field:
func textChanged(sender:AnyObject) {
let tf = sender as UITextField
var resp : UIResponder = tf
while !(resp is UIAlertController) { resp = resp.nextResponder() }
let alert = resp as UIAlertController
(alert.actions[1] as UIAlertAction).enabled = (tf.text != "")
}
EDIT Here's the current (Swift 3.0.1 and later) version of the above code:
alert.addTextField { tf in
tf.addTarget(self, action: #selector(self.textChanged), for: .editingChanged)
}
and
alert.actions[1].isEnabled = false
and
#objc func textChanged(_ sender: Any) {
let tf = sender as! UITextField
var resp : UIResponder! = tf
while !(resp is UIAlertController) { resp = resp.next }
let alert = resp as! UIAlertController
alert.actions[1].isEnabled = (tf.text != "")
}
I've simplified matt's answer without the view hierarcy traversing. This is holding the action itself as a weak variable instead. This is a fully working example:
weak var actionToEnable : UIAlertAction?
func showAlert()
{
let titleStr = "title"
let messageStr = "message"
let alert = UIAlertController(title: titleStr, message: messageStr, preferredStyle: UIAlertControllerStyle.Alert)
let placeholderStr = "placeholder"
alert.addTextFieldWithConfigurationHandler({(textField: UITextField) in
textField.placeholder = placeholderStr
textField.addTarget(self, action: "textChanged:", forControlEvents: .EditingChanged)
})
let cancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (_) -> Void in
})
let action = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: { (_) -> Void in
let textfield = alert.textFields!.first!
//Do what you want with the textfield!
})
alert.addAction(cancel)
alert.addAction(action)
self.actionToEnable = action
action.enabled = false
self.presentViewController(alert, animated: true, completion: nil)
}
func textChanged(sender:UITextField) {
self.actionToEnable?.enabled = (sender.text! == "Validation")
}
Cribbing off of #Matt's answer, here's how I did the same thing in Obj-C
- (BOOL)textField: (UITextField*) textField shouldChangeCharactersInRange: (NSRange) range replacementString: (NSString*)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange: range withString: string];
// check string length
NSInteger newLength = [newString length];
BOOL okToChange = (newLength <= 16); // don't allow names longer than this
if (okToChange)
{
// Find our Ok button
UIResponder *responder = textField;
Class uiacClass = [UIAlertController class];
while (![responder isKindOfClass: uiacClass])
{
responder = [responder nextResponder];
}
UIAlertController *alert = (UIAlertController*) responder;
UIAlertAction *okAction = [alert.actions objectAtIndex: 0];
// Dis/enable Ok button based on same-name
BOOL duplicateName = NO;
// <check for duplicates, here>
okAction.enabled = !duplicateName;
}
return (okToChange);
}
I realise that this is in Objectiv-C but it shows the principal. I will update this with a swift version later.
You could also do the same using a block as the target.
Add a property to your ViewController so that the block (closure for swift) has a strong reference
#property (strong, nonatomic) id textValidationBlock;
Then create the AlertViewController like so:
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Title" message:#"Message" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
__weak typeof(self) weakSelf = self;
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[weakSelf doSomething];
}];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[alertController.actions lastObject].enabled = NO;
self.textValidationBlock = [^{
UITextField *textField = [alertController.textFields firstObject];
if (something) {
alertController.message = #"Warning message";
[alertController.actions lastObject].enabled = NO;
} else if (somethingElse) {
alertController.message = #"Another warning message";
[alertController.actions lastObject].enabled = NO;
} else {
//Validation passed
alertController.message = #"";
[alertController.actions lastObject].enabled = YES;
}
} copy];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = #"placeholder here";
[textField addTarget:weakSelf.textValidationBlock action:#selector(invoke) forControlEvents:UIControlEventEditingChanged];
}];
[self presentViewController:alertController animated:YES completion:nil];
Here's the same idea as in other answers, but I wanted a simple method isolated in an extension and available for use in any UIViewController subclass. It shows an alert with one text input field and two buttons: ok and cancel.
extension UIViewController {
func askForTextAndConfirmWithAlert(title: String, placeholder: String, okHandler: #escaping (String?)->Void) {
let alertController = UIAlertController(title: title, message: nil, preferredStyle: .alert)
let textChangeHandler = TextFieldTextChangeHandler { text in
alertController.actions.first?.isEnabled = !(text ?? "").isEmpty
}
var textHandlerKey = 0
objc_setAssociatedObject(self, &textHandlerKey, textChangeHandler, .OBJC_ASSOCIATION_RETAIN)
alertController.addTextField { textField in
textField.placeholder = placeholder
textField.clearButtonMode = .whileEditing
textField.borderStyle = .none
textField.addTarget(textChangeHandler, action: #selector(TextFieldTextChangeHandler.onTextChanged(sender:)), for: .editingChanged)
}
let okAction = UIAlertAction(title: CommonLocStr.ok, style: .default, handler: { _ in
guard let text = alertController.textFields?.first?.text else {
return
}
okHandler(text)
objc_setAssociatedObject(self, &textHandlerKey, nil, .OBJC_ASSOCIATION_RETAIN)
})
okAction.isEnabled = false
alertController.addAction(okAction)
alertController.addAction(UIAlertAction(title: CommonLocStr.cancel, style: .cancel, handler: { _ in
objc_setAssociatedObject(self, &textHandlerKey, nil, .OBJC_ASSOCIATION_RETAIN)
}))
present(alertController, animated: true, completion: nil)
}
}
class TextFieldTextChangeHandler {
let handler: (String?)->Void
init(handler: #escaping (String?)->Void) {
self.handler = handler
}
#objc func onTextChanged(sender: AnyObject) {
handler((sender as? UITextField)?.text)
}
}
I want to add 3 TextFields in UIAlertView like oldpassword, Newpassword, confirmpassword like this.
Here is my code i tried
-(IBAction)changePswd:(id)sender
{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Change Password" message:#"Enter Your New Password" delegate:self cancelButtonTitle:#"cancel" otherButtonTitles:#"submit", nil];
[alertView setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
[[alertView textFieldAtIndex:0]setSecureTextEntry:YES];
[alertView textFieldAtIndex:0].keyboardType = UIKeyboardTypeDefault;
[alertView textFieldAtIndex:0].returnKeyType = UIReturnKeyDone;
[[alertView textFieldAtIndex:0]setPlaceholder:#"Enter Your Old Password"];
[[alertView textFieldAtIndex:1]setPlaceholder:#"Enter password"];
[[alertView textFieldAtIndex:2]setPlaceholder:#"Re-Enter Password"];
[alertView show];
}
it shows only two textfields.
Use UIAlertController for this.
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
__block typeof(self) weakSelf = self;
//old password textfield
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField)
{
textField.tag = 1001;
textField.delegate = weakSelf;
textField.placeholder = #"Old Password";
textField.secureTextEntry = YES;
[textField addTarget:weakSelf action:#selector(alertTextFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
}];
//new password textfield
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField)
{
textField.tag = 1002;
textField.delegate = weakSelf;
textField.placeholder = #"New Password";
textField.secureTextEntry = YES;
}];
//confirm password textfield
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField)
{
textField.tag = 1003;
textField.delegate = weakSelf;
textField.placeholder = #"Confirm Password";
textField.secureTextEntry = YES;
[textField addTarget:weakSelf action:#selector(alertTextFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
}];
[self presentViewController:alertController animated:YES completion:nil];
#pragma mark - UITextField Delegate Methods
- (void)alertTextFieldDidChange:(UITextField *)sender
{
alertController = (UIAlertController *)self.presentedViewController;
UITextField *firstTextField = alertController.textFields[0];
}
swift 2.0 :
1) Making a public variable
var alertController: UIAlertController?
2) Setting up Alert Controller
alertController = UIAlertController(title: "Alert Title", message: "Alert Message", preferredStyle: .Alert)
//old password textfield
alertController!.addTextFieldWithConfigurationHandler({(textField: UITextField!) in
textField.placeholder = "Password"
textField.secureTextEntry = true
textField.addTarget(self, action: "alertTextFieldDidChange:", forControlEvents: .EditingChanged)
})
//new password textfield
alertController!.addTextFieldWithConfigurationHandler({(textField: UITextField) -> Void in
textField.tag = 1002
textField.placeholder = "New Password"
textField.secureTextEntry = true
textField.addTarget(self, action: "alertTextFieldDidChange:", forControlEvents: .EditingChanged)
})
//confirm password textfield
alertController!.addTextFieldWithConfigurationHandler({(textField: UITextField) -> Void in
textField.tag = 1003
textField.placeholder = "Confirm Password"
textField.addTarget(self, action: "alertTextFieldDidChange:", forControlEvents: .EditingChanged)
})
alertController!.addAction(UIAlertAction(title: "Submit", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
//Do after submit is clicked
}))
alertController!.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
self.alertController?.dismissViewControllerAnimated(true, completion: nil)
}))
self.presentViewController(alertController!, animated: true, completion: nil)
3) Taking TextField values
func alertTextFieldDidChange(sender: UITextField) {
alertController = self.presentedViewController as? UIAlertController
let firstTextField: UITextField = (alertController?.textFields![0])!
let secondTextField: UITextField = (alertController?.textFields![1])!
let thirdTextField: UITextField = (alertController?.textFields![2])!
print(firstTextField.text)
print(secondTextField.text)
print(thirdTextField.text)
}
Note:
this is the right way:
let title = "Your Title"
let message = "Your message"
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
now add textfields
alertController.addTextField { (textField : UITextField!) -> Void in
textField.placeholder = "Your placeholder..."
textField.tintColor = .yourColor
textField.secureTextEntry = true
}
alertController.addTextField { (textField2 : UITextField!) -> Void in
textField2.placeholder = "Your placeholder2..."
textField2.tintColor = . yourColor
textField2.secureTextEntry = true
}
add first action
let firstAction = UIAlertAction(title: "Save Text", style: .default, handler: { alert -> Void in
guard let textField = alertController.textFields else { return }
let firstTextField = textField[0] as UITextField
let secondTextField = textField[1] as UITextField
//insert your code here
print(secondTextField.text ?? "")
print(firstTextField.text ?? "")
})
add Cancel action
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (cancel) in
print("Action cancelled")
}
add actions to alert controller
alertController.addAction(firstAction)
alertController.addAction(cancelAction)
now present alertController
self.present(alertController, animated: true, completion: nil)
put this code in your function, modify with your parameters and call it wherever you want...
I want to realize a function about changing password. It requires users to input their previous password in an alert dialog.
I want to click the button "Confirm the modification" then jump to the other view controller for changing password. I have written some code, but I don't know how to write in the next moment.
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Change password" message:#"Please input your previous password" preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = #"please input your previous password";
textField.secureTextEntry = YES;
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"cancel" style:UIAlertActionStyleCancel handlers:nil];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"Confirm the modification" style:UIAlertActionStyleDestructive handler:*(UIAlertAction *alertAction) {
if (condition) {
statements
}
}];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[self presentViewController:alertController animated:YES completion:nil];
You will get all added textfields from alert controller by its textFields readonly property, you can use it to get its text.
Like
Swift 4:
let alertController = UIAlertController(title: "", message: "", preferredStyle: .alert)
alertController.addTextField { textField in
textField.placeholder = "Password"
textField.isSecureTextEntry = true
}
let confirmAction = UIAlertAction(title: "OK", style: .default) { [weak alertController] _ in
guard let alertController = alertController, let textField = alertController.textFields?.first else { return }
print("Current password \(String(describing: textField.text))")
//compare the current password and do action here
}
alertController.addAction(confirmAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
Note: textField.text is optional, unwrap it before using
Objective-C:
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"" message:#"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = #"Current password";
textField.secureTextEntry = YES;
}];
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(#"Current password %#", [[alertController textFields][0] text]);
//compare the current password and do action here
}];
[alertController addAction:confirmAction];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
NSLog(#"Canelled");
}];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
By [[alertController textFields][0] text] this line, it will take first textfield added to the alerController and get its text.
You can add multiple textfields to alert controller and access them with the alert controller's textFields property
If the new password is an empty string, present the alert again. Or another way would be to disable the "Confirm" button, enabling it only when text field has text.
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"confirm the modification" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
UITextField *password = alertController.textFields.firstObject;
if (![password.text isEqualToString:#""]) {
//change password
}
else{
[self presentViewController:alertController animated:YES completion:nil];
}
}];
Here is an updated answer for Swift 4.0 that creates the desired kind of textfield:
// Create a standard UIAlertController
let alertController = UIAlertController(title: "Password Entry", message: "", preferredStyle: .alert)
// Add a textField to your controller, with a placeholder value & secure entry enabled
alertController.addTextField { textField in
textField.placeholder = "Enter password"
textField.isSecureTextEntry = true
textField.textAlignment = .center
}
// A cancel action
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { _ in
print("Canelled")
}
// This action handles your confirmation action
let confirmAction = UIAlertAction(title: "OK", style: .default) { _ in
print("Current password value: \(alertController.textFields?.first?.text ?? "None")")
}
// Add the actions, the order here does not matter
alertController.addAction(cancelAction)
alertController.addAction(confirmAction)
// Present to user
present(alertController, animated: true, completion: nil)
And how it looks when first presented:
And while accepting text:
Swift 5.1
#objc func promptAddDialog() {
let ac = UIAlertController.init(title: "Enter answer", message: nil, preferredStyle: .alert)
ac.addTextField{ textField in
textField.placeholder = "Answer"
textField.textAlignment = .center
}
let submitAction = UIAlertAction(title: "Submit", style: .default) {
[weak self, weak ac] _ in
guard let answer = ac?.textFields?[0].text else { return }
self?.submit(answer)
}
ac.addAction(submitAction)
present(ac, animated: true)
}
I want to add text input in alert-view of ios 8.
I know it was done using UIAlertController but not have any idea.
How to do it ?
Screenshot
Code
UIAlertController * alertController = [UIAlertController alertControllerWithTitle: #"Login"
message: #"Input username and password"
preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = #"name";
textField.textColor = [UIColor blueColor];
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.borderStyle = UITextBorderStyleRoundedRect;
}];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = #"password";
textField.textColor = [UIColor blueColor];
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.secureTextEntry = YES;
}];
[alertController addAction:[UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
NSArray * textfields = alertController.textFields;
UITextField * namefield = textfields[0];
UITextField * passwordfiled = textfields[1];
NSLog(#"%#:%#",namefield.text,passwordfiled.text);
}]];
[self presentViewController:alertController animated:YES completion:nil];
AlertViewController
// use UIAlertController
UIAlertController *alert= [UIAlertController
alertControllerWithTitle:#"Title"
message:#"SubTitle"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action){
//Do Some action here
UITextField *textField = alert.textFields[0];
NSLog(#"text was %#", textField.text);
}];
UIAlertAction* cancel = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
NSLog(#"cancel btn");
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:ok];
[alert addAction:cancel];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = #"placeHolderText";
textField.keyboardType = UIKeyboardTypeDefault;
}];
[self presentViewController:alert animated:YES completion:nil];
UIAlertView
UIAlertView* dialog = [[UIAlertView alloc] initWithTitle:#"Title"
message:#"SubTitle"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
dialog.alertViewStyle = UIAlertViewStylePlainTextInput;
[dialog show];
}
Example of implementation with Swift 3:
var textField: UITextField?
// create alertController
let alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .alert)
alertController.addTextField { (pTextField) in
pTextField.placeholder = "usefull placeholdr"
pTextField.clearButtonMode = .whileEditing
pTextField.borderStyle = .none
textField = pTextField
}
// create cancel button
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (pAction) in
alertController.dismiss(animated: true, completion: nil)
}))
// create Ok button
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (pAction) in
// when user taps OK, you get your value here
let inputValue = textField?.text
alertController.dismiss(animated: true, completion: nil)
}))
// show alert controller
self.present(alertController, animated: true, completion: nil)
UIAlertView *myView = [[UIAlertView alloc]initWithTitle:#"Input" message:#"Enter your value" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
myView.alertViewStyle = UIAlertViewStylePlainTextInput;
[myView textFieldAtIndex:0].delegate = self;
[myView show];
you can cover this way .Thanks
UIAlertView *av = [[UIAlertView alloc]initWithTitle:#"Title" message:#"Please enter someth" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
av.alertViewStyle = UIAlertViewStylePlainTextInput;
[av textFieldAtIndex:0].delegate = self;
[av show];
also, you will need to implement UITextFieldDelegate, UIAlertViewDelegate protocols.
and if you user uialertcontroller then use this one
UIAlertController * alert= [UIAlertController
alertControllerWithTitle:#"My Title"
message:#"Enter User Credentials"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//Do Some action here
}];
UIAlertAction* cancel = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:ok];
[alert addAction:cancel];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = #"Username";
}];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = #"Password";
textField.secureTextEntry = YES;
}];
[self presentViewController:alert animated:YES completion:nil];
Here's handy method with submit/cancel and completion handler for text if inputted:
/**
Presents an alert controller with a single text field for user input
- parameters:
- title: Alert title
- message: Alert message
- placeholder: Placeholder for textfield
- completion: Returned user input
*/
func showSubmitTextFieldAlert(title: String,
message: String,
placeholder: String,
completion: #escaping (_ userInput: String?) -> Void) {
let alertController = UIAlertController(title: title,
message: message,
preferredStyle: .alert)
alertController.addTextField { (textField) in
textField.placeholder = placeholder
textField.clearButtonMode = .whileEditing
}
let submitAction = UIAlertAction(title: "Submit", style: .default) { (action) in
let userInput = alertController.textFields?.first?.text
completion(userInput)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in
completion(nil)
}
alertController.addAction(submitAction)
alertController.addAction(cancelAction)
present(alertController, animated: true)
}
This one is work for me:
let passwordString = lableGetPassword.text
var textField: UITextField?
// create alertController
let alertController = UIAlertController(title: "Password", message: "Save the password. Give a tag name.", preferredStyle: .alert)
alertController.addTextField { (pTextField) in
pTextField.placeholder = "Tag Name"
pTextField.clearButtonMode = .whileEditing
pTextField.borderStyle = .none
textField = pTextField
}
// create cancel button
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (pAction) in
alertController.dismiss(animated: true, completion: nil)
}))
// create Ok button
alertController.addAction(UIAlertAction(title: "Save", style: .default, handler: { [self] (pAction) in
// when user taps OK, you get your value here
let name = textField?.text
save(name: name!, password: passwordString!)
alertController.dismiss(animated: true, completion: nil)
}))
// show alert controller
self.present(alertController, animated: true, completion: nil)
UIAlertViewController with text input
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Title"
message:nil
preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
// optionally configure the text field
textField.keyboardType = UIKeyboardTypeAlphabet;
}];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
UITextField *textField = [alert.textFields firstObject];
textField.placeholder = #"Enter Input";
}];
[alert addAction:okAction];
[self presentViewController:alert animated:YES completion:nil];
func askForName() {
let alert = UIAlertController(title: "Enter Text",
message: "Enter some text below",
preferredStyle: .alert)
alert.addTextField { (textField) in
textField.text = "New Text"
}
let action = UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert!.textFields![0]
print("Text field: \(textField.text)")
})
alert.addAction(action)
present(alert, animated: true, completion: nil)
}
Can anyone tell me how to validate UITextFields inside of a UIAlertController?
I need it to prevent the user from clicking "Save" unless both fields are entered.
Here is my code so far:
#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)
}
This is my function for validating the Email field:
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
}
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...
Swift 3.0 example
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)
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)
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)
This can be achieved via NSNotificationCenter before you display the alert controller, all you have to do is ask the notification center to observe the notification for UITextFieldTextDidChangeNotification and you should be good,
Given below is the implementation for the same
#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
}
You can use below code to validate TextFields in an UIAlertController :-
Step 1:
Declare "email_TF" to your viewcontroller.h
for example:
#property(strong,nonatomic)UITextField *email_TF;
Step 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;
}];
Step 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 (example#example.com 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];
Step 4:
[self presentViewController:alert animated:YES completion:nil];
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)
//...
I implemented a UIAlertController subclass which allows you to add a handler on text field changes when you add it to the alert:
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)
}
}
}
So for your case the only extra thing that need to be added is to call the isValidEmail function in the textChangeAction handler:
alert.addTextField(configurationHandler: { (textField) in
// things you want to configure on the textfield
}) { (textField) in
saveAction.isEnabled = isValidEmail(textField.text ?? "")
}
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];
First, you need to add some variables to your class:
private weak var saveAction : UIAlertAction?
private weak var textFieldName : UITextField?
private weak var textFieldEmail : UITextField?
private var validName = false
private var validEmail = false
Then, when you want to configure the alert controller (I only pasted the things that need to be changed):
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
Finally, you should implement this delegate method:
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
}