diff --git a/MVMCoreUI/FormUIHelpers/FormValidator.swift b/MVMCoreUI/FormUIHelpers/FormValidator.swift index a0785c41..090202c0 100644 --- a/MVMCoreUI/FormUIHelpers/FormValidator.swift +++ b/MVMCoreUI/FormUIHelpers/FormValidator.swift @@ -96,8 +96,13 @@ import MVMCore public func validateGroup(_ group: FormGroupRule) -> Bool { // Validate each rule. var valid = true + var previousValidity: [String: Bool] = [:] for rule in group.rules { - valid = valid && rule.validate(fields) + let tuple = rule.validate(fields, previousValidity) + let temp = tuple.0 + let returnedValidity = tuple.1 + previousValidity = previousValidity.merging(returnedValidity) { (_, new) in new } + valid = valid && temp } // Notify the group watchers of validity. diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift index 7f153e83..2addbf90 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyRequiredModel.swift @@ -36,15 +36,23 @@ public class RuleAnyRequiredModel: RulesProtocol { return false } - public func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { - + public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidiity: [String: Bool]) -> (Bool, [String: Bool]) { + + var previousValidity: [String: Bool] = [:] for formKey in fields { guard let formField = fieldMolecules[formKey] else { continue } - - if isValid(formField) { - return true + + var fieldValidity = isValid(formField) + // If past rule is invalid forr a field, the current rule should not flip the validity of a field + if let validity = previousFieldValidiity[formKey], !validity, fieldValidity { + fieldValidity = false } + + if fieldValidity { + return (fieldValidity, previousValidity) + } + previousValidity[formKey] = false } - return false + return (false, previousValidity) } } diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift index 07cf451f..d7413419 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift @@ -27,13 +27,21 @@ public class RuleAnyValueChangedModel: RulesProtocol { return formField.baseValue != formField.formFieldValue() } - public func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { + public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidiity: [String: Bool]) -> (Bool, [String: Bool]) { + var previousValidity: [String: Bool] = [:] for formKey in fields { guard let formField = fieldMolecules[formKey] else { continue } - if isValid(formField) { - return true + var fieldValidity = isValid(formField) + // If past rule is invalid forr a field, the current rule should not flip the validity of a field + if let validity = previousFieldValidiity[formKey], !validity, fieldValidity { + fieldValidity = false } + + if fieldValidity { + return (true, previousValidity) + } + previousValidity[formKey] = false } - return false + return (false, previousValidity) } } diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift index 5e014cff..4979adf2 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsIgnoreCaseModel.swift @@ -27,10 +27,11 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol { return false } - public func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { - var valid = false - var compareText: String? + public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidiity: [String: Bool]) -> (Bool, [String: Bool]) { + var valid = false + var compareText: String? + var previousValidity: [String: Bool] = [:] for formKey in fields { guard let formField = fieldMolecules[formKey] else { continue } @@ -42,16 +43,24 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol { if let fieldValue = formField.formFieldValue() as? String, compareString.caseInsensitiveCompare(fieldValue) == .orderedSame { valid = true + + var fieldValidity = valid + // If past rule is invalid forr a field, the current rule should not flip the validity of a field + if let validity = previousFieldValidiity[formKey], !validity, fieldValidity { + fieldValidity = false + } + for formKey in fields { guard let formField = fieldMolecules[formKey] else { continue } (formField as? FormRuleWatcherFieldProtocol)?.setValidity(true, rule: self) } break } - + + previousValidity[formKey] = valid (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) } - return valid + return (valid, previousValidity) } } diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift index fa73ed51..7795ab39 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleEqualsModel.swift @@ -27,9 +27,10 @@ public class RuleEqualsModel: RulesProtocol { return false } - public func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { - var valid = true - var compareValue: AnyHashable? + public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidiity: [String: Bool]) -> (Bool, [String: Bool]) { + var valid = true + var compareValue: AnyHashable? + var previousValidity: [String: Bool] = [:] for formKey in fields { guard let formField = fieldMolecules[formKey] else { continue } @@ -41,13 +42,19 @@ public class RuleEqualsModel: RulesProtocol { if compareValue != formField.formFieldValue() { valid = false + previousValidity[formKey] = valid (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) break } else { - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(valid, rule: self) + var fieldValidity = valid + // If past rule is invalid forr a field, the current rule should not flip the validity of a field + if let validity = previousFieldValidiity[formKey], !validity, fieldValidity { + fieldValidity = false + } + (formField as? FormRuleWatcherFieldProtocol)?.setValidity(fieldValidity, rule: self) } } - return valid + return (valid, previousValidity) } } diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift index 5a8b47a8..c48fd111 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RulesProtocol.swift @@ -26,7 +26,7 @@ public protocol RulesProtocol: ModelProtocol { func isValid(_ formField: FormFieldProtocol) -> Bool // Validates the rule and returns the result. - func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool + func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidiity: [String: Bool]) -> (Bool, [String: Bool]) } public extension RulesProtocol { @@ -38,14 +38,21 @@ public extension RulesProtocol { static var categoryName: String { "\(RulesProtocol.self)" } // Individual rule can override the function to validate based on the rule type. - func validate(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { - var valid = true - for formKey in fields { - guard let formField = fieldMolecules[formKey] else { continue } - let fieldValidity = isValid(formField) - (formField as? FormRuleWatcherFieldProtocol)?.setValidity(fieldValidity, rule: self) - valid = valid && fieldValidity - } - return valid + func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidiity: [String: Bool]) -> (Bool, [String: Bool]) { + var valid = true + var previousValidity: [String: Bool] = [:] + for formKey in fields { + guard let formField = fieldMolecules[formKey] else { continue } + + var fieldValidity = isValid(formField) + // If past rule is invalid forr a field, the current rule should not flip the validity of a field + if let validity = previousFieldValidiity[formKey], !validity, fieldValidity { + fieldValidity = false + } + (formField as? FormRuleWatcherFieldProtocol)?.setValidity(fieldValidity, rule: self) + valid = valid && fieldValidity + previousValidity[formKey] = fieldValidity + } + return (valid, previousValidity) } }