First cut at form fiedable change

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2024-02-29 10:34:10 -06:00
parent 05638422f6
commit 69a2374504
5 changed files with 97 additions and 14 deletions

View File

@ -31,7 +31,7 @@ extension LabelAttributeModel {
}
public func isValidRange(on attributedString: NSMutableAttributedString) -> Bool {
true//range.location + range.length <= attributedString.string.count
range.location + range.length <= attributedString.string.count
}
}

View File

@ -13,7 +13,7 @@ import Combine
/// Base Class used to build out a Input controls.
@objc(VDSEntryField)
open class EntryFieldBase: Control, Changeable {
open class EntryFieldBase: Control, Changeable, FormFieldable {
//--------------------------------------------------
// MARK: - Initializers
@ -196,7 +196,7 @@ open class EntryFieldBase: Control, Changeable {
open var inputId: String? { didSet { setNeedsUpdate() } }
open var value: AnyHashable? { didSet { setNeedsUpdate() } }
open var value: String? { didSet { setNeedsUpdate() } }
open var defaultValue: AnyHashable? { didSet { setNeedsUpdate() } }

View File

@ -79,13 +79,13 @@ open class InputField: EntryFieldBase, UITextFieldDelegate {
open var fieldType: FieldType = .text { didSet { setNeedsUpdate() } }
/// The text of this textField.
open override var text: String? {
open override var value: String? {
get { textField.text }
set {
textField.text = newValue
}
}
var _showError: Bool = false
/// Whether not to show the error.
open override var showError: Bool {

View File

@ -107,14 +107,15 @@ open class TextArea: EntryFieldBase {
}
}
/// The text of this textField.
open override var text: String? {
open override var value: String? {
get { textView.text }
set {
textView.text = newValue
setNeedsUpdate()
}
}
/// UITextView shown in the TextArea.
open var textView = TextView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
@ -184,7 +185,7 @@ open class TextArea: EntryFieldBase {
/// Used to make changes to the View based off a change events or from local properties.
open override func updateView() {
super.updateView()
countRule.maxLength = maxLength
textView.isEditable = isEnabled
textView.isEnabled = isEnabled
textView.surface = surface
@ -208,6 +209,9 @@ open class TextArea: EntryFieldBase {
} else {
characterCounterLabel.text = ""
}
showError = !validator.validate()
errorText = validator.errorMessage
icon.size = .medium
icon.color = iconColorConfiguration.getColor(self)
@ -246,12 +250,8 @@ open class TextArea: EntryFieldBase {
let countStr = (count > maxLength ?? 0) ? ("-" + "\(count-(maxLength ?? 0))") : "\(count)"
if ((maxLength ?? 0) > 0) {
if (count > (maxLength ?? 0)) {
showError = true
errorText = "You have exceeded the character limit."
return countStr
} else {
showError = false
errorText = ""
return ("\(countStr)" + "/" + "\(maxLength ?? 0)")
}
} else {
@ -274,6 +274,33 @@ open class TextArea: EntryFieldBase {
textView.textAttributes = textAttributes
}
//--------------------------------------------------
// MARK: - Validation
//--------------------------------------------------
var countRule = CharacterCountRule()
lazy var validator: FieldValidator<TextArea> = {
let validator = FieldValidator<TextArea>(field: self, rules: [.init(countRule)])
return validator
}()
class CharacterCountRule: Rule {
var maxLength: Int?
var errorMessage: String = "You have exceeded the character limit."
func isValid(value: String?) -> Bool {
guard let text = value else { return true }
if ((maxLength ?? 0) > 0) {
if (text.count > (maxLength ?? 0)) {
return false
} else {
return true
}
}
return true
}
}
}
extension TextArea: UITextViewDelegate {

View File

@ -9,10 +9,66 @@ import Foundation
/// Protocol used for a FormField object.
public protocol FormFieldable {
associatedtype ValueType = AnyHashable
/// Unique Id for the Form Field object within a Form.
var inputId: String? { get set }
/// Value for the Form Field.
var value: AnyHashable? { get set }
var value: ValueType? { get set }
}
public struct AnyRule<ValueType> {
private let _isValid: (ValueType?) -> Bool
public let errorMessage: String
init<R: Rule>(_ rule: R) where R.ValueType == ValueType {
self._isValid = rule.isValid
self.errorMessage = rule.errorMessage
}
public func isValid(value: Any?) -> Bool {
guard let typedValue = value as? ValueType? else {
return false
}
return _isValid(typedValue)
}
}
public protocol Rule<ValueType> {
associatedtype ValueType
func isValid(value: ValueType?) -> Bool
var errorMessage: String { get }
}
public class FieldValidator<Field:FormFieldable>{
public var field: Field
public var rules: [AnyRule<Field.ValueType>]?
public var errorMessages = [String]()
public init(field: Field, rules: [AnyRule<Field.ValueType>]? = nil) {
self.field = field
self.rules = rules
}
public var errorMessage: String? {
errorMessages.joined(separator: "\r")
}
public func validate() -> Bool{
errorMessages.removeAll()
guard let rules else {
return true
}
for rule in rules {
if !rule.isValid(value: field.value) {
errorMessages.append(rule.errorMessage)
return false
}
}
return true
}
}