swift - 使用复选框按钮 RxCocoa/RxSwift 验证表单
问题描述
我需要使用单选按钮验证表单,但我做不到,我分享我的代码:
我的观点:
private func registerForm() {
tvUserName.rx.text.map { $0 ?? "" }.bind(to: viewModel.userNamePublishSubject).disposed(by: disposeBag)
tvEmail.rx.text.map { $0 ?? "" }.bind(to: viewModel.emailPublishSubject).disposed(by: disposeBag)
tvPassword.rx.text.map { $0 ?? "" }.bind(to: viewModel.passwordPublishSubject).disposed(by: disposeBag)
tvRepeatPassword.rx.text.map { $0 ?? "" }.bind(to: viewModel.repeatPasswordPublishSubject).disposed(by: disposeBag)
viewModel.formLoginNativaIsValid().bind(to: btnNext.rx.isEnabled).disposed(by: disposeBag)
checkBoxOutlet.rx.tap
.scan(false) { lastValue, _ in
return !lastValue
}
.bind(to: btnNext.rx.isEnabled)
.disposed(by: disposeBag)
}
我的视图模型:
let userNamePublishSubject = PublishSubject<String>()
let emailPublishSubject = PublishSubject<String>()
let passwordPublishSubject = PublishSubject<String>()
let repeatPasswordPublishSubject = PublishSubject<String>()
func formLoginNativaIsValid() -> Observable<Bool> {
return Observable.combineLatest(userNamePublishSubject.asObserver(),
emailPublishSubject.asObserver(),
passwordPublishSubject.asObserver(),
repeatPasswordPublishSubject.asObserver()).map { userName, email, password, repeatPassword in
return self.validateRegister(userName: userName, email: email, password: password,
repeatPassword: repeatPassword)
}.startWith(false)
}
private func validateRegister(userName: String, email: String, password: String, repeatPassword: String) -> Bool {
return userName.count >= 5 && email.isEmail() && password.count >= 5 && repeatPassword.count >= 5 && password == repeatPassword
}
我已经验证了表单,但我还需要用户接受启用“下一步”按钮的条款和条件。
解决方案
在设计反应式系统时,您需要考虑因果关系。每个可观察的链都应该关注一个单一的效果,并根据需要引入尽可能多的原因。就像一个函数有几个参数传入并返回一个值一样。
在这种情况下,您的效果是btnNext.rx.isEnabled
。你必须考虑是什么导致这种影响发生变化?这是我将如何编写它的示例:
class View: UIView {
weak var tvUserName: UITextView!
weak var tvEmail: UITextView!
weak var tvPassword: UITextView!
weak var tvRepeatPassword: UITextView!
weak var btnNext: UIButton!
weak var checkBoxOutlet: UIButton!
let disposeBag = DisposeBag()
override func awakeFromNib() {
super.awakeFromNib()
isNextButtonEnabled(
username: tvUserName.rx.text.orEmpty.asObservable(),
email: tvEmail.rx.text.orEmpty.asObservable(),
password: tvPassword.rx.text.orEmpty.asObservable(),
repeatPassword: tvRepeatPassword.rx.text.orEmpty.asObservable(),
checkBox: checkBoxOutlet.rx.tap.asObservable()
)
.bind(to: btnNext.rx.isEnabled)
.disposed(by: disposeBag)
}
}
func isNextButtonEnabled(username: Observable<String>, email: Observable<String>, password: Observable<String>, repeatPassword: Observable<String>, checkBox: Observable<Void>) -> Observable<Bool> {
return Observable.combineLatest(
[
username.map { $0.count >= 5 },
email.map { $0.isEmail() },
password.map { $0.count >= 5 },
Observable.combineLatest(password, repeatPassword) { $0 == $1 },
checkBox.scan(false) { state, _ in !state }.startWith(false)
]
)
.map { $0.allSatisfy { $0 } }
}
请注意您的视图模型在这里是多么简单。就是isNextButtonEnabled
功能。它可以很容易地测试,但非常简单,您甚至可能觉得不需要测试。确定下一个按钮是否启用的所有条件都集中在一个地方以便于理解。不需要一堆 PublishSubjects。它更容易阅读和理解。
推荐阅读
- android - 使用 ConstraintLayout 的片段 onCreateView 不遵守 ConstraintSet
- reactjs - 单击时如何将数据从一个反应组件传递到另一个反应组件
单击时如何将数据从一个反应组件传递到另一个反应组件
[ { "id": 1, "title": "XYZ Title", "body": "www.xyz.com sample hits", "comments": [ { "id": 1, "postId": 1, "name": null,
- java - 如何从 Java 中的用户输入中获取日期?
- c# - LinqKit 嵌套调用“LINQ to Entities 无法识别方法‘Invoke’”
- python-3.x - 有没有一种简单的方法来初始化一个以 NoneType 为键的字典?
- flutter - Flutter:无法使用 dio 获取数组 json 到对象列表
- java - 如何为 Android 生成常量 UUId?
- sql-server - 使用 SQL 发布 XML 不起作用,但 Postman 工作正常
- regex - 正则表达式仅在单独时捕获相同的单词
- swift - 绑定到枚举的关联值