Merge pull request #3 from davepatterson/remote-validation
Added Remote validation to validator.
This commit is contained in:
commit
d4aa8e594f
|
|
@ -1,9 +1,4 @@
|
|||
SwiftValidator
|
||||
===============
|
||||
|
||||
[](https://travis-ci.org/jpotts18/SwiftValidator) [](https://github.com/Carthage/Carthage)
|
||||
[](https://coveralls.io/github/davepatterson/SwiftValidator?branch=travis-edit)
|
||||
|
||||
=======
|
||||
[](https://travis-ci.org/jpotts18/SwiftValidator) [](https://github.com/Carthage/Carthage) [](https://codecov.io/github/jpotts18/SwiftValidator?branch=master)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = "SwiftValidator"
|
||||
s.version = "3.0.1"
|
||||
s.version = "3.0.4"
|
||||
s.summary = "A UITextField Validation library for Swift"
|
||||
s.homepage = "https://github.com/jpotts18/SwiftValidator"
|
||||
s.screenshots = "https://raw.githubusercontent.com/jpotts18/SwiftValidator/master/swift-validator-v2.gif"
|
||||
|
|
@ -9,7 +9,7 @@ Pod::Spec.new do |s|
|
|||
s.social_media_url = "http://twitter.com/jpotts18"
|
||||
s.platform = :ios
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.source = { :git => "https://github.com/jpotts18/SwiftValidator.git", :tag => "3.0.1" }
|
||||
s.source = { :git => "https://github.com/jpotts18/SwiftValidator.git", :tag => "3.0.4" }
|
||||
s.source_files = "SwiftValidator/**/*.swift"
|
||||
s.exclude_files = "Validator/AppDelegate.swift"
|
||||
s.frameworks = ['Foundation', 'UIKit']
|
||||
|
|
|
|||
|
|
@ -13,15 +13,21 @@ import UIKit
|
|||
*/
|
||||
@objc public protocol ValidationDelegate {
|
||||
/**
|
||||
This method will be called on delegate object when validation is successful.
|
||||
This delegate method will be called on delegate object when validation is successful.
|
||||
- returns: No return value.
|
||||
*/
|
||||
func validationSuccessful()
|
||||
/**
|
||||
This method will be called on delegate object when validation fails.
|
||||
This delegae method will be called on delegate object when validation fails.
|
||||
- returns: No return value.
|
||||
*/
|
||||
func validationFailed(errors: [UITextField:ValidationError])
|
||||
|
||||
optional func remoteRequest(text: String, urlString: String, completion:(result: Bool) -> Void)
|
||||
/**
|
||||
This delegate method is called on fields that require remote validation.
|
||||
- parameter text: String to is sent to server to be validated.
|
||||
- parameter urlString: String of url endpoint that will be used to validate text.
|
||||
- parameter completion: closure that holds the result of the server validation request. Should be set to true if server validation was a success. Should return false if server validation failed.
|
||||
- returns: No return value.
|
||||
*/
|
||||
optional func remoteValidationRequest(text: String, urlString: String, completion:(result: Bool) -> Void)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import UIKit
|
|||
/**
|
||||
Class that makes `Validator` objects. Should be added as a parameter to ViewController that will display
|
||||
validation fields.
|
||||
*/
|
||||
*/
|
||||
public class Validator {
|
||||
/// Dictionary to hold all fields (and accompanying rules) that will undergo validation.
|
||||
public var validations = [UITextField:ValidationRule]()
|
||||
|
|
@ -54,12 +54,19 @@ public class Validator {
|
|||
}
|
||||
}
|
||||
}
|
||||
/// Validate all fields with completion handler
|
||||
|
||||
/**
|
||||
This method is used to validate all fields registered to Validator. If validation is unsuccessful,
|
||||
field gets added to errors dictionary. Completion closure is used to validator know when all fields
|
||||
have undergone validation attempt.
|
||||
- parameter completion: Bool that is set to true when all fields have experienced validation attempt.
|
||||
- returns: No return value.
|
||||
*/
|
||||
private func validateAllFields(completion: (finished: Bool) -> Void) {
|
||||
errors = [:]
|
||||
|
||||
for (textField, rule) in validations {
|
||||
if rule.remoteURLString != nil {
|
||||
if rule.remoteInfo != nil {
|
||||
validateRemoteField(textField, completion: { status -> Void in
|
||||
self.completedValidationsCount = self.completedValidationsCount + 1
|
||||
if self.completedValidationsCount == self.validations.count {
|
||||
|
|
@ -77,40 +84,67 @@ public class Validator {
|
|||
}
|
||||
}
|
||||
}
|
||||
/// Validate remote field
|
||||
|
||||
/**
|
||||
This method is used to validate a field that will need to also be validated via remote request.
|
||||
- parameter textField: TextField of field that is being validated.
|
||||
- parameter completion: Closure that holds the status of textField's validation. Is set to true
|
||||
after remote validation has ended, regardless of whether the validation was a success or failure.
|
||||
- returns: No return value.
|
||||
*/
|
||||
private func validateRemoteField(textField: UITextField, completion: (status: Bool) -> Void) {
|
||||
if let fieldRule = validations[textField] {
|
||||
delegate!.remoteRequest!(textField.text!, urlString: fieldRule.remoteURLString!, completion: { result -> Void in
|
||||
if result {
|
||||
// Carry on with validation as remote validation passed
|
||||
self.validateRegularField(fieldRule.textField)
|
||||
} else {
|
||||
// Stop validation because remote validation failed
|
||||
// Validation Failed on remote call
|
||||
let error = ValidationError(textField: fieldRule.textField, errorLabel: UILabel(), error: "Field already taken")
|
||||
self.errors[fieldRule.textField] = error
|
||||
if let transform = self.errorStyleTransform {
|
||||
transform(validationError: error)
|
||||
// Carry on with validation as regular validation passed
|
||||
if self.validateRegularField(fieldRule.textField) {
|
||||
delegate!.remoteValidationRequest!(textField.text!, urlString: fieldRule.remoteInfo!.urlString, completion: { result -> Void in
|
||||
if result {
|
||||
if let transform = self.successStyleTransform {
|
||||
transform(validationRule: fieldRule)
|
||||
}
|
||||
} else {
|
||||
// Stop validation because remote validation failed
|
||||
// Validation Failed on remote call
|
||||
let error = ValidationError(textField: fieldRule.textField, errorLabel: fieldRule.errorLabel, error: fieldRule.remoteInfo!.error)
|
||||
self.errors[fieldRule.textField] = error
|
||||
if let transform = self.errorStyleTransform {
|
||||
transform(validationError: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Validation is over, so let validateAllFields(completion: (status: Bool)) know
|
||||
completion(status: true)
|
||||
})
|
||||
} else {
|
||||
// Validation is over, so let validateAllFields(completion: (status: Bool)) know
|
||||
completion(status: true)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/// Validate regular field (non-remote)
|
||||
private func validateRegularField(textField: UITextField) {
|
||||
|
||||
/**
|
||||
Method used to validate a regular field (non-remote).
|
||||
- parameter: TextField of field that is undergoing validation
|
||||
- returns: A Bool that represents whether the validation was a success or failure, returns true for the
|
||||
former and false for the latter.
|
||||
*/
|
||||
private func validateRegularField(textField: UITextField) -> Bool {
|
||||
if let fieldRule = validations[textField] {
|
||||
if let error = fieldRule.validateField() {
|
||||
errors[textField] = error
|
||||
if let transform = self.errorStyleTransform {
|
||||
transform(validationError: error)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if let transform = self.successStyleTransform {
|
||||
transform(validationRule: fieldRule)
|
||||
if fieldRule.remoteInfo == nil {
|
||||
transform(validationRule: fieldRule)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MARK: Public functions
|
||||
|
|
@ -160,9 +194,9 @@ public class Validator {
|
|||
- parameter textField: field that is to be validated.
|
||||
- parameter Rule: An array which holds different rules to validate against textField.
|
||||
- returns: No return value
|
||||
*/
|
||||
public func registerField(textField:UITextField, rules:[Rule], remoteURLString: String? = nil) {
|
||||
validations[textField] = ValidationRule(textField: textField, rules: rules, errorLabel: nil, remoteURLString: remoteURLString)
|
||||
*/
|
||||
public func registerField(textField:UITextField, rules:[Rule], remoteInfo: (String, String)? = nil) {
|
||||
validations[textField] = ValidationRule(textField: textField, rules: rules, errorLabel: nil, remoteInfo: remoteInfo)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -172,9 +206,9 @@ public class Validator {
|
|||
- parameter errorLabel: A UILabel that holds error label data
|
||||
- parameter rules: A Rule array that holds different rules that apply to said textField.
|
||||
- returns: No return value
|
||||
*/
|
||||
public func registerField(textField:UITextField, errorLabel:UILabel, rules:[Rule]) {
|
||||
validations[textField] = ValidationRule(textField: textField, rules:rules, errorLabel:errorLabel)
|
||||
*/
|
||||
public func registerField(textField:UITextField, errorLabel:UILabel, rules:[Rule], remoteInfo: (String, String)? = nil) {
|
||||
validations[textField] = ValidationRule(textField: textField, rules:rules, errorLabel:errorLabel, remoteInfo: remoteInfo)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -182,7 +216,7 @@ public class Validator {
|
|||
|
||||
- parameter textField: field used to locate and remove textField from validator.
|
||||
- returns: No return value
|
||||
*/
|
||||
*/
|
||||
public func unregisterField(textField:UITextField) {
|
||||
validations.removeValueForKey(textField)
|
||||
errors.removeValueForKey(textField)
|
||||
|
|
@ -192,7 +226,7 @@ public class Validator {
|
|||
This method checks to see if all fields in validator are valid.
|
||||
|
||||
- returns: No return value.
|
||||
*/
|
||||
*/
|
||||
public func validate(delegate:ValidationDelegate) {
|
||||
|
||||
self.validateAllFields()
|
||||
|
|
@ -206,12 +240,30 @@ public class Validator {
|
|||
}
|
||||
|
||||
/**
|
||||
This method validates all fields in validator and sets any errors to errors parameter of callback.
|
||||
This method attempts to validate all fields registered to Validator().
|
||||
- returns: No return value.
|
||||
*/
|
||||
public func validate() {
|
||||
self.validateAllFields { finished -> Void in
|
||||
if self.errors.isEmpty {
|
||||
// call success method if it's implemented
|
||||
self.delegate!.validationSuccessful()
|
||||
} else {
|
||||
// call failure method if it's implemented
|
||||
self.delegate!.validationFailed(self.errors)
|
||||
}
|
||||
// set number of completed validations back to 0
|
||||
self.completedValidationsCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This method validates all fields in validator and sets any errors to errors parameter of closure.
|
||||
|
||||
- parameter callback: A closure which is called with errors, a dictionary of type UITextField:ValidationError.
|
||||
|
||||
- returns: No return value.
|
||||
*/
|
||||
*/
|
||||
public func validate(callback:(errors:[UITextField:ValidationError])->Void) -> Void {
|
||||
|
||||
self.validateAllFields()
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ public class ValidationRule {
|
|||
public var errorLabel:UILabel?
|
||||
/// the rules of the field
|
||||
public var rules:[Rule] = []
|
||||
public var remoteURLString: String?
|
||||
/// tuple that holds remote validatin info
|
||||
public var remoteInfo: (urlString: String, error: String)?
|
||||
//public var remoteURLString: String?
|
||||
|
||||
/**
|
||||
Initializes `ValidationRule` instance with text field, rules, and errorLabel.
|
||||
|
|
@ -32,7 +34,14 @@ public class ValidationRule {
|
|||
self.textField = textField
|
||||
self.errorLabel = errorLabel
|
||||
self.rules = rules
|
||||
self.remoteURLString = remoteURLString
|
||||
//self.remoteURLString = remoteURLString
|
||||
}
|
||||
|
||||
public init(textField: UITextField, rules:[Rule], errorLabel:UILabel?, remoteInfo: (String, String)? = nil){
|
||||
self.textField = textField
|
||||
self.errorLabel = errorLabel
|
||||
self.rules = rules
|
||||
self.remoteInfo = remoteInfo
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -50,33 +50,58 @@ class ViewController: UIViewController , ValidationDelegate, UITextFieldDelegate
|
|||
})
|
||||
|
||||
validator.registerField(fullNameTextField, errorLabel: fullNameErrorLabel , rules: [RequiredRule(), FullNameRule()])
|
||||
validator.registerField(emailTextField, errorLabel: emailErrorLabel, rules: [RequiredRule(), EmailRule()])
|
||||
validator.registerField(emailTextField, errorLabel: emailErrorLabel, rules: [RequiredRule(), EmailRule()], remoteInfo: (urlString: "http://localhost:8000/emails/", error: "Email already in use"))
|
||||
validator.registerField(emailConfirmTextField, errorLabel: emailConfirmErrorLabel, rules: [RequiredRule(), ConfirmationRule(confirmField: emailTextField)])
|
||||
validator.registerField(phoneNumberTextField, errorLabel: phoneNumberErrorLabel, rules: [RequiredRule(), MinLengthRule(length: 9)])
|
||||
validator.registerField(zipcodeTextField, errorLabel: zipcodeErrorLabel, rules: [RequiredRule(), ZipCodeRule()])
|
||||
validator.delegate = self
|
||||
}
|
||||
|
||||
@IBAction func submitTapped(sender: AnyObject) {
|
||||
print("Validating...")
|
||||
validator.validate(self)
|
||||
validator.validate()
|
||||
}
|
||||
|
||||
func simulateRemoteRequest(seconds: Int64, completion: (result: Bool) -> Void) {
|
||||
print("Simulating \(seconds) second server request...")
|
||||
// Set number of seconds before "request" is finished
|
||||
let triggerTime = (Int64(NSEC_PER_SEC) * seconds)
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, triggerTime), dispatch_get_main_queue(), { () -> Void in
|
||||
// For example purposes, if user does not enter David Patterson as full name,
|
||||
// the email they tried will be already taken
|
||||
if self.fullNameTextField.text! == "David Patterson" {
|
||||
completion(result: true)
|
||||
} else {
|
||||
completion(result: false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func hideKeyboard(){
|
||||
self.view.endEditing(true)
|
||||
}
|
||||
|
||||
// MARK: ValidationDelegate Methods
|
||||
|
||||
func validationSuccessful() {
|
||||
print("Validation Success!")
|
||||
let alert = UIAlertController(title: "Success", message: "You are validated!", preferredStyle: UIAlertControllerStyle.Alert)
|
||||
let alert = UIAlertController(title: "Success", message: "You are validated, \(fullNameTextField.text!)!", preferredStyle: UIAlertControllerStyle.Alert)
|
||||
let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
|
||||
alert.addAction(defaultAction)
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
|
||||
}
|
||||
|
||||
func validationFailed(errors:[UITextField:ValidationError]) {
|
||||
print("Validation FAILED!")
|
||||
}
|
||||
|
||||
func hideKeyboard(){
|
||||
self.view.endEditing(true)
|
||||
func remoteValidationRequest(text: String, urlString: String, completion: (result: Bool) -> Void) {
|
||||
simulateRemoteRequest(2) { result -> Void in
|
||||
// Set result to true if field was validated server-side
|
||||
// Set to false if field was not validated server-side
|
||||
completion(result: result)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Validate single field
|
||||
|
|
|
|||
Loading…
Reference in New Issue