Enable UIAlertAction of UIAlertController only after input is validated
Add following property in your header file
@property(nonatomic, strong)UIAlertAction *okAction;
then copy the following code in your viewDidLoad
method of your ViewController
self.okAction = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil];
self.okAction.enabled = NO;
UIAlertController *controller = [UIAlertController alertControllerWithTitle:nil
message:@"Enter your text"
preferredStyle:UIAlertControllerStyleAlert];
[controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.delegate = self;
}];
[controller addAction:self.okAction];
[self presentViewController:controller animated:YES completion:nil];
Also implement the following UITextField
delegate method in your Class
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSString *finalString = [textField.text stringByReplacingCharactersInRange:range withString:string];
[self.okAction setEnabled:(finalString.length >= 5)];
return YES;
}
This should work
Check on UIAlertController TextField for enabling the button
I would first create the alertcontroller with the save action initially disabled. Then when adding the textfield inculde a Notification to observe its change in the handler and in that selector just toggle the save actions enabled property.
Here is what I am saying:
//hold this reference in your class
weak var AddAlertSaveAction: UIAlertAction?
@IBAction func addTherapy(sender : AnyObject) {
//set up the alertcontroller
let title = NSLocalizedString("New Prescription", comment: "")
let message = NSLocalizedString("Insert a name for this prescription.", comment: "")
let cancelButtonTitle = NSLocalizedString("Cancel", comment: "")
let otherButtonTitle = NSLocalizedString("Save", comment: "")
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
// Add the text field with handler
alertController.addTextFieldWithConfigurationHandler { textField in
//listen for changes
NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleTextFieldTextDidChangeNotification:", name: UITextFieldTextDidChangeNotification, object: textField)
}
func removeTextFieldObserver() {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextFieldTextDidChangeNotification, object: alertController.textFields[0])
}
// Create the actions.
let cancelAction = UIAlertAction(title: cancelButtonTitle, style: .Cancel) { action in
NSLog("Cancel Button Pressed")
removeTextFieldObserver()
}
let otherAction = UIAlertAction(title: otherButtonTitle, style: .Default) { action in
NSLog("Save Button Pressed")
removeTextFieldObserver()
}
// disable the 'save' button (otherAction) initially
otherAction.enabled = false
// save the other action to toggle the enabled/disabled state when the text changed.
AddAlertSaveAction = otherAction
// Add the actions.
alertController.addAction(cancelAction)
alertController.addAction(otherAction)
presentViewController(alertController, animated: true, completion: nil)
}
//handler
func handleTextFieldTextDidChangeNotification(notification: NSNotification) {
let textField = notification.object as UITextField
// Enforce a minimum length of >= 1 for secure text alerts.
AddAlertSaveAction!.enabled = textField.text.utf16count >= 1
}
I am doing this in another project - I got this pattern directly from apple examples. They have a very good example project outlining a few of these patterns in the UICatalog examples: https://developer.apple.com/library/content/samplecode/UICatalog/Introduction/Intro.html
How do I validate TextFields in an UIAlertController?
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)
}
how to disable the both uialertcontroller button when no input in uitext field of uialertview controller
Disable the buttons initially and then once you have something in your text field re-enable them.
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Info"
message:@"You are using UIAlertController with Actionsheet and text fields"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction
actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
NSLog(@"Resolving UIAlert Action for tapping OK Button");
[alert dismissViewControllerAnimated:YES completion:nil];
}];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:@"Cancel"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
NSLog(@"Resolving UIAlertActionController for tapping cancel button");
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[ok setEnabled:false];
[cancel setEnabled:false];
[alert addAction:ok];
[alert addAction:cancel];
For adding the selector to the text field and then handling it:
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = @"iCloud ID";
textField.textColor = [UIColor blueColor];
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.borderStyle = UITextBorderStyleRoundedRect;
[textField addTarget:self action:@selector(textDidChange:) forControlEvents:UIControlEventEditingChanged];
}];
- (void)textDidChange:(UITextField *)textField {
if (textField.text.length > 0) {
// enable the buttons
}
}
For handling textfield delegates you can go through the following posts:
- Access input from UIAlertController
- Check on UIAlertController TextField for enabling the button
Prevent dismissal of UIAlertController
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 != "")
}
shouldChangeCharactersInRange is not getting called
phoneNumberTF
is not a part of UIAlertController
so no need of delegate for this phoneNumberTF.delegate = self;
add the configuration delegate to your UIAlertController
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Enter your phone number" message:nil preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField)
{
textField.delegate = self;
}];
for more info you get the sample here
How do you disable a UIAlertAction depending on a UITextField in a UIAlertController?
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 ...
How to enable/disable Alert action?
Do this
textField.addTarget(self, action: #selector(self.textEdited), for: .editingChanged)
@objc func textEdited(_ textField:UITextField) {
if textField.text!.count > 0 {
alert.actions.first?.isEnabled = true
}else{
alert.actions.first?.isEnabled = false
}
}
Add this line that will disable it initially
alert.actions.first?.isEnabled = false
self.present(alert, animated: true)
Related Topics
Application Identifier Entitlement Value Has Changed
Get the Callers Phone Number from an Incoming Call on Iphone
How to Add Custom Text in Nsdateformatter's Format String
Ios7 App Backward Compatible with iOS5 Regarding Unique Identifier
How Get the List of Paired Bluetooth Devices in Swift
Gamecenter iOS 9 Gamecenter Gklocalplayerlistener Methods Not Called
Detecting Tap Inside a Bezier Path
Aws Cognito iOS Developer Authenticated Identities
Uisearchbar's Cancel and Clear Buttons Not Working in iOS 7
Best Analytics Offering for Iphone
Ignore Manual Entries from Apple Health App as Data Source
Swift String Escaping When Serializing to JSON Using Codable
How to Call Https Url in Uiwebview
Warning in Custom Map Annotations Iphone
iOS 9 Cloudkit: Query Does Not Return Anything While Connected to Cellular Network