Reputation: 751
So I have an UIAlertController, with 2 textfields, I then want to monitor whenever those textfields are edited to see if they meet a certain criteria.
In this case, I want my alert button to be inactive as long as both textfields input is shorter than a number I want to pass to the function.
So I added this target to both textfields:
textField.addTarget(self, action: #selector(self.handleTextFieldEdit), for: .editingChanged)
inside handleTextFieldEdit I have this:
func handleTextFieldEdit(_ textField: UITextField, number: Int)
{
let number = number
let alertController:UIAlertController = self.presentedViewController as! UIAlertController;
let textField: UITextField = alertController.textFields![0]
let confirmField: UITextField = alertController.textFields![1]
let addAction: UIAlertAction = alertController.actions[0];
if ((textField.text?.characters.count)! > number && (confirmField.text?.characters.count)! > number)
{
addAction.isEnabled = true
}
else if ((textField.text?.characters.count)! <= number || (confirmField.text?.characters.count)! <= number )
{
addAction.isEnabled = false
}
}
Now my first problem is I can't seem to pass any variables with a #selector func.
My second problem is I don't know what to pass to _ textField: UITextField
I have tried both UITextField and textField (which is what I declared my UITextFields to).
The error that comes up is: Cannot convert value of type 'UITextField'.Type to expected argument type 'UITextField'.
EDIT: All of my code works whenever I don't pass a variable with the function btw. The problem is I want the minimum value to be changed whenever I call the function.
Upvotes: 3
Views: 2680
Reputation:
Here's some tested code. Basically, I've subclassed UIAlertViewController
, adding functions to add UITextFields
and a UIAlertAction
.
The text fields are created by passing a tuple (Int,String) containing the minimum length and placeholder values. The OK button is disabled upon creation.
Internally, I've added your handleTextFieldEdit()
function, but refactored. It sets a Bool
in a second array - you could simply use a single array but this is simply an example - and then calls a new function to set the okButton.isEnabled
property.
In my UIViewController
:
public func showAlert(_ title:String, _ message:String) {
// use the subclassed UIAlertViewController
// - add two text fields with minimum length and placeholders
// - add an OK button
let alertVC = MyAlertController(
title: "MyTitle",
message: "MyMessage",
preferredStyle: .alert)
alertVC.addTextFields([(5,"Enter First Name"),(10,"Enter Last Name")])
alertVC.addOkAction()
present(
alertVC,
animated: true,
completion: nil)
}
And my subclassed UIAlertViewController:
class MyAlertController: UIAlertController {
var textMinLengths = [Int]()
var textMinLengthsReached = [Bool]()
var okAction:UIAlertAction!
// add UITextFields:
// - append textMinLengths[]
// - set placeholder
// - append "false" to textMinLengthsReached[]
// - set tag value to array index
// - add target action handleTextFieldEdit()
func addTextFields(_ textConfigs:[(Int,String)]) {
var tagValue:Int = 0
for textConfig in textConfigs {
textMinLengths.append(textConfig.0)
textMinLengthsReached.append(false)
self.addTextField { (textField : UITextField!) -> Void in
textField.placeholder = textConfig.1
textField.tag = tagValue
textField.addTarget(self, action: #selector(self.handleTextFieldEdit(_:)), for: .editingChanged) }
tagValue += 1
}
}
// add a *disabled* OK button
func addOkAction() {
okAction = UIAlertAction(
title: "OK",
style: .cancel,
handler: { action -> Void in
})
self.addAction(okAction)
okAction.isEnabled = false
}
// every keystroke, check the character count against the minimum, setting if it's been reached,
// always checking whether to show alert action afterwards
func handleTextFieldEdit(_ sender: UITextField) {
if (sender.text?.characters.count)! >= textMinLengths[sender.tag] {
textMinLengthsReached[sender.tag] = true
} else {
textMinLengthsReached[sender.tag] = false
}
showAlertAction()
}
// loop through textMinLengthsReached, setting okButton.isEnabled
func showAlertAction() {
var isEnabled = true
for textMinLengthReached in textMinLengthsReached {
if !textMinLengthReached {
isEnabled = false
break
}
}
okAction.isEnabled = isEnabled
}
}
Upvotes: 1
Reputation: 598
in order to track changes in text field some object must be delegate of this text field
for example when you create AlertController with text field inside you should assign delegate to it.
somewhere inside of method of some YourViewController:
self.alertView = UIAlertController.init(title: "Your title", message: Your message", preferredStyle: .alert)
self.alertView.addTextField(configurationHandler: { textfield in
textfield.font = UIFont.fontProximaNovaLight(18)
textfield.textColor = UIColor.colorAppLightGray2()
textfield.keyboardType = .default
textfield.delegate = self
})
Extending your viewController:
extension YourViewController: UITextFieldDelegate {
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let text = textField.text?.replacingCharacters( in: range.toRange(textField.text!), with: string)
// some test verification
// for example you can use your function to verify textfield against value
// validate (textfield, number)
if text?.characters.count > 0 {
self.alertView.actions[0].isEnabled = true
} else {
self.alertView.actions[0].isEnabled = false
}
return true
}
}
Upvotes: 0
Reputation: 558
Subclass UITextField and add another property to be used for your length requirement. Then you can read it as part of the sender.
Upvotes: 0
Reputation: 131408
You're trying to add an EXTRA parameter (an int) to an IBAction
selector. You can't do that. IBActions have one of 3 selectors:
@IBAction func actionNoParams() {
}
@IBAction func actionWSender(_ sender: Any) {
}
@IBAction func actionWSenderAndEvent(_ sender: Any, forEvent event: UIEvent) {
}
Those are your only options. You can't add additional parameters, or change the type of either of the possible parameters.
The system calls your function when the control needs to invoke the target/action.
(Any time you add a target/action to a control you must use one of the function signatures above, even if you don't label your function with the @IBAction
keyword (Which you should really be doing, BTW.)
Upvotes: 2
Reputation: 437
Try below code
textField.addTarget(self, action: #selector(self.handleTextFieldEdit(sender:)), for: .editingChanged)
func handleTextFieldEdit(sender: UITextField) {
}
Upvotes: 0