Reputation: 2777
I'm new to RxSwift
and want to achieve the following. I have a email and password TextField
. When you've entered a text in both textfields
a button should be enabled.
In my ViewController I do the following:
txtEmail.rx.text.asObservable()
.bindTo(viewModel.email)
.addDisposableTo(disposeBag)
txtPassword.rx.text.asObservable()
.bindTo(viewModel.password)
.addDisposableTo(disposeBag)
viewModel.buttonEnabled
.bindTo(btnLogin.rx.isEnabled)
.addDisposableTo(disposeBag)
And here is my ViewModel:
import Foundation
import RxSwift
import RxCocoa
class LoginViewModel {
let email = Variable<String?>("")
let password = Variable<String?>("")
var buttonEnabled: Observable<Bool>
init() {
var processedEmail: Observable<String>!
var processedPassword: Observable<String>!
processedEmail = email.asObservable().map(String.toLower as! (String?) -> String).map(String.trimWhiteSpace as! (String?) -> String)
processedPassword = password.asObservable().map(String.toLower as! (String?) -> String).map(String.trimWhiteSpace as! (String?) -> String)
let emailValid = processedEmail.asObservable().map(String.isNotEmpty)
let passwordValid = processedPassword.asObservable().map(String.isNotEmpty)
buttonEnabled = Observable.combineLatest(emailValid, passwordValid) {
return $0 && $1
}
}
func didTapLoginButton() {
print("hello \(email.value)")
}
}
For some reason the init
method of my viewmodel
never gets finished.
Can someone help me?
Upvotes: 1
Views: 2184
Reputation: 51
I tried this example of init and it seems working:
init() {
let processedEmail = email.asObservable()
.map { $0 ?? "" }
.map { $0.lowercased() }
.map { !$0.isEmpty }
let processedPassword = password.asObservable()
.map { $0 ?? "" }
.map { $0.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) }
.map { !$0.isEmpty }
buttonEnabled = Observable.combineLatest(processedEmail, processedPassword) {
return $0 && $1
}
}
Upvotes: 1
Reputation: 13651
It seems like the definition of processedEmail
and processedPassword
are generating the crash preventing the view model init to complete.
More specifically, the String.toLower
and String.trimWhiteSpace
method probably have type (String) -> String
but here they are force cast to (String?) -> String
.
processedEmail = email.asObservable()
.map { $0 ?? "" }
.map(String.toLower)
.map(String.trimWhiteSpace)
processedPassword = password.asObservable()
.map { $0 ?? "" }
.map(String.toLower)
.map(String.trimWhiteSpace)
I've only added .map { $0 ?? "" }
. Because the original observable has type Observable<String?>
the map call will transform it to Observable<String>
which will then be processable by String.toLower
and String.trimWhiteSpace
Upvotes: 3