我正在使用反应式swift进行表单验证.但我面临重置价值和信号价值的问题.
当我按照验证规则的指示正确填充所有文本字段时,所有信号(textfield continuoustextvalues)都会产生真值,这将允许我发送表单数据.完成表单提交后,我重置了textfield的值.之后,我向所有信号Observer发送false值.但是当我开始填充文本字段时,它将获得以前的真实信号,并允许我在不应用任何验证规则的情况下发送数据.这意味着我无法重置信号值
任何帮助将非常感激.
我的问题:
import UIKit import ReactiveSwift import Result class ContactVC: BaseViewController { @IBOutlet weak var textFieldName: JVFloatLabeledTextField! @IBOutlet weak var textFieldPhoneOL: JVFloatLabeledTextField! @IBOutlet weak var textViewComent: UITextView! @IBOutlet weak var textFieldLocationOL: JVFloatLabeledTextField! @IBOutlet weak var textFieldEmailOL: JVFloatLabeledTextField! @IBOutlet weak var btnSubmitOL: PGSpringAnimation! var (nameValidationSignal, nameValidationObserver) = Signal.pipe() var (phoneValidationSignal, phoneValidationObserver) = Signal .pipe() var (emailValidationSignal, emailValidationObserver) = Signal .pipe() var (locationValidationSignal, locationValidationObserver) = Signal .pipe() var (commentValidationSignal, commentValidationObserver) = Signal .pipe() override func viewDidLoad() { super.viewDidLoad() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) self.formValidation() } // MARK: - submit button action @IBAction func btnSubmitAction(_ sender: Any) { let params = ["name":textFieldName.text!,"email":textFieldEmailOL.text!,"location":textFieldLocationOL.text!,"message":textViewComent.text!,"phone":textFieldPhoneOL.text!] APIManager(urlString:enumUrl.ContactAdmin.mainURL(),parameters:params as [String : AnyObject]?,method: .post).handleResponse(viewController: self, progressMessage: "downloading", completionHandler: { (response : AllResponse) in self.nameValidationObserver.send(value: false) self.emailValidationObserver.send(value: false) self.phoneValidationObserver.send(value: false) self.locationValidationObserver.send(value: false) self.commentValidationObserver.send(value: false) self.btnSubmitOL.backgroundColor = UIColor.gray self.btnSubmitOL.isUserInteractionEnabled = false }) } // MARK: - validation textfield func formValidation(){ self.btnSubmitOL.backgroundColor = UIColor.gray self.btnSubmitOL.isUserInteractionEnabled = false // Create signals // Signals for TextFields self.nameValidationSignal = self.textFieldName.reactive.continuousTextValues .map{ ($0?.characters.count ?? 0) >= 3 } self.phoneValidationSignal = self.textFieldPhoneOL.reactive.continuousTextValues .map{ ($0?.characters.count ?? 0 ) >= 8 } self.emailValidationSignal = self.textFieldEmailOL.reactive.continuousTextValues .map{ $0?.isEmail ?? false } self.locationValidationSignal = self.textFieldLocationOL.reactive.continuousTextValues .map{ ($0?.characters.count ?? 0) >= 3 } self.commentValidationSignal = self.textViewComent.reactive.continuousTextValues .map{ ($0?.characters.count ?? 0) >= 5 } // Observe TextFields Singals for Changing UI self.nameValidationSignal.observeValues { value in self.textFieldName.floatingLabelActiveTextColor = value ? UIColor.red : UIColor.black self.textFieldName.floatingLabel.text = value ? "name".localize : "Name must be greater than 4 characters".localize } self.phoneValidationSignal.observeValues { value in self.textFieldPhoneOL.floatingLabelActiveTextColor = value ? UIColor.red : UIColor.black self.textFieldPhoneOL.floatingLabel.text = value ? "phone".localize : "Phone must be greater than 7 characters".localize } self.emailValidationSignal.observeValues { value in self.textFieldEmailOL.floatingLabelActiveTextColor = value ? UIColor.red : UIColor.black self.textFieldEmailOL.floatingLabel.text = value ? "email".localize : "Email must be of type example@test.com".localize } self.locationValidationSignal.observeValues { value in self.textFieldLocationOL.floatingLabelActiveTextColor = value ? UIColor.red : UIColor.black self.textFieldLocationOL.floatingLabel.text = value ? "location".localize : "Loation must be greater than 4 characters".localize } self.commentValidationSignal.observeValues { value in self.textViewComent.textColor = value ? UIColor.red : UIColor.black } let formValidationSignal = nameValidationSignal.combineLatest(with: phoneValidationSignal).combineLatest(with: emailValidationSignal).combineLatest(with: locationValidationSignal).combineLatest(with: commentValidationSignal) .map { $0.0.0.0 && $0.0.0.1 && $0.0.1 && $0.1 && $1 } formValidationSignal.observeValues { self.btnSubmitOL.isUserInteractionEnabled = $0 self.btnSubmitOL.backgroundColor = $0 ? UIColor.appRedColor() : UIColor.gray } } }
我已经解决了这个问题,但我不认为这是完美的方式,并且反应不是我要解决的问题.我正在等待完美或最受欢迎的解决方案.任何帮助或答案都是真正的赞赏.
以下是我对此的看法,采用更惯用的方法(为了示例,简化为仅两个输入).
首先,有一个ViewModel,它有MutableProperty
s来保存输入值.您可以将这些值初始化为除了nil
您想要输入的其他初始值之外的任何其他值.
ViewModel als具有用于验证输入的属性.
Property.map
用于从输入推断有效值.顺便说一句,你可以用Signal.combineLatest(signal1, signal2, signal3, ...)
而不是signal1.combineLatest(with: signal2).combineLatest(with: signal3)...
最后,有一个Action
执行提交.在ViewController中,我们可以将它绑定Action
到按钮.Action每次执行时都会发送一个空字符串.的.values
动作的信号被用于执行该动作之后复位的输入.如果提交可能产生错误,您应该相应地处理.
class ViewModel { let username = MutableProperty(nil) let address = MutableProperty (nil) let usernameValid: Property let addressValid: Property let valid: Property let submit: Action<(String?, String?), String, NoError> init() { self.usernameValid = username.map { return ($0 ?? "").characters.count > 0 } self.addressValid = address.map { return ($0 ?? "").characters.count > 0 } self.valid = Property.combineLatest(self.usernameValid, self.addressValid).map { (usernameValid, addressValid) in return usernameValid && addressValid } self.submit = Action(enabledIf: self.valid) { input in print("Submit with username \(input.0) and address \(input.1)") return SignalProducer (value: "") } self.username <~ self.submit.values self.address <~ self.submit.values } }
然后是ViewController中的设置:
override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.username.reactive.text <~ self.viewModel.username self.address.reactive.text <~ self.viewModel.address self.viewModel.username <~ self.username.reactive.continuousTextValues self.viewModel.address <~ self.address.reactive.continuousTextValues self.submit.reactive.pressed = CocoaAction(self.viewModel.submit) { [weak self] (button) -> (String?, String?) in return (self?.username.text, self?.address.text) } }
首先,MutableProperty
ViewModel的UITextField
s 绑定到s.这样,文本字段不仅初始化为ViewModel中属性的初始值,而且如果ViewModel中的属性更新,它们也会更新 - 这样,您可以在执行提交操作时重置它们.
随后,continuousTextValues
的UITextFields
绑定到视图模型的属性.因为continuousTextValues
如果以编程方式设置文本,则不会触发,仅当用户设置了文本时,才会创建循环.
最后,CocoaAction
用于将submit
操作绑定到按钮的pressed
Action.该inputTransformer
功能用于在每次按下按钮时发送输入的当前值.
您还可以订阅viewModel 的各个usernameValid
/ addressValid
属性,以在此处向用户设置显示验证错误.