Search code examples
swiftvalidationuitextfieldtextfielduitextfielddelegate

textField Maximum length and Postal Code validation


I have a textField to input a Canadian postal code. And I am using the following code to ensure the formatting is correct or else show an alert saying the formatting is incorrect. This is working with no problem on saveBtnClick; but I cant type in the field as it continues returning false into the textField because of the validZipCode function.I also need make sure the maximum length of characters for this field does not exceed 7 characters so the user cant type more than seven characters. I see many solutions only for setting the maximum length; but cant figure out how to do this with an existing condition that I mentioned here for postal code validation. Here is my current code:

@IBOutlet weak var postalCodeTextField: UITextField!

override func viewDidLoad() {
    phoneNumberTextField.delegate = self
    postalCodeTextField.delegate = self
}

func validZipCode(postalCode:String)->String{
    let postalcodeRegex = "^[a-zA-Z][0-9][a-zA-Z][- ]*[0-9][a-zA-Z][0-9]$"
    let pinPredicate = NSPredicate(format: "SELF MATCHES %@", postalcodeRegex)
    let bool = pinPredicate.evaluate(with: postalCode) as Bool
  return bool.description
}

@IBAction func saveBtnClicked(_ sender: Any) {

    let isPostalCodeValid = validZipCode(postalCode: postalCodeTextField.text ?? "")

    if isPostalCodeValid == "false" {

        simpleAlert(title: "Error!", msg: "Please enter a valid CA postal code")

    } else
        if isPostalCodeValid == "true" {
       //the postalCaode is correct formatting
    }

}




func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard let text = textField.text else { return false }
        let newString = (text as NSString).replacingCharacters(in: range, with: string)

    if textField == phoneNumberTextField {
        textField.text = formattedNumber(number: newString)
    } else

        if textField == postalCodeTextField {
            textField.text = validZipCode(postalCode: newString)
    }

    return false
}

Solution

  • The function validZipCode would always return false if we pass single character to it. So ,validate the predicate on click of saveButton.

    class ViewController: UIViewController, UITextFieldDelegate {
        @IBOutlet weak var postalCodeTextField: UITextField!
    
           override func viewDidLoad() {
                postalCodeTextField.delegate = self
            }
    
            func validZipCode(postalCode:String)->Bool{
                  let postalcodeRegex = "^[a-zA-Z][0-9][a-zA-Z][- ]*[0-9][a-zA-Z][0-9]$"
                let pinPredicate = NSPredicate(format: "SELF MATCHES %@", postalcodeRegex)
                let bool = pinPredicate.evaluate(with: postalCode) as Bool
                return bool
            }
    
            @IBAction func saveBtnClicked(_ sender: Any) {
    
                let isPostalCodeValid = validZipCode(postalCode: postalCodeTextField.text ?? "")
    
                if isPostalCodeValid == false {
                    print("false")
                   // simpleAlert(title: "Error!", msg: "Please enter a valid CA postal code")
    
                } else
                    if isPostalCodeValid == true {
                        print("true")
                   //the postalCaode is correct formatting
                }
    
            }
    
            func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
                let currentText = textField.text ?? ""
                 guard let stringRange = Range(range, in: currentText) else { return false }
    
                if textField == postalCodeTextField {
                    // add their new text to the existing text
                    let updatedText = currentText.replacingCharacters(in: stringRange, with: string)
    
                    // make sure the result is under 7 characters
                    return updatedText.count <= 7
                }else{
                    return true
                }
            }
    
        }
    

    Hope this helps !!