In RxSwift/RxCocoa 2.0.0- beta 3, I have a ViewModel with:
let someString = Variable("")
func isValidSomeString() -> Observable<Bool> {
if someString.value.characters.count == 0 {
return just(false)
}
return just(true)
}
I have the someString bound already to a text field in the ViewController.
Whenever the someString (or perhaps the text field if that's a better way) changes, I want a button enabled based on if someString is valid.
I tried using the "Observable< Bool >", but started going down another path. I could do this in the ViewController:
someViewModel.someString.subscribeNext { text -> Void in
// could just someUIButton.enabled = someViewModel.isValidSomeString(text)
}.addDisposableTo(disposeBag)
Isn't there another way that is less verbose than the isValidSomeString(text) approach? We already have had nice success with a isValidLogin that returns Observable< Bool > which used combineLatest.
Sounds like Action
is the perfect tool to use in this case. You'll want to create an Action
in your ViewModel, let its enabledIf
observable be the result of changes to the string, and connect this action to your UIButton
. This way the button will be auto-enabled.
In your ViewModel, you'll need to add this:
var buttonAction: CocoaAction {
let hasString = self.someString.map { !$0.isEmpty }
return CocoaAction(enabledIf: hasString) {
// do something when button tapped
return empty()
}
}
And when binding your ViewController to your ViewModel, you'll do:
myButton.rx_action = viewModel.buttonAction
Looks like you just need to map
your someString
to Obserable<Bool>
and then bind it to rx_enabled
of UIButton
Something like this:
someViewModel.someString
.asObservable()
.map { (str) -> Bool in
return someViewModel.isValidSomeString(text)
}
.bindTo(someUIButton.rx_enabled)
.addDisposableTo(disposeBag)
but I think it whould be simpler if you would have Variable<Bool>
in your viewmodel kind of
struct ViewModel {
....
canLogIn = Variable(false)
}
In this case you will be able bind it to rx_enabled
like this:
let userNameValidation = loginTextField
.rx_text
.map({!$0.isEmpty})
.shareReplay(1)
let passwordValidation = passwordTextField
.rx_text
.map({!$0.isEmpty})
.shareReplay(1)
let loginEnabled = combineLatest(userNameValidation, passWordValidation) { (username, password) in
return username && password
}
loginEnabled
.bindTo(loginViewModel.canlogIn)
.addDisposableTo(disposeBag)
loginViewModel.canlogIn
.bindTo(loginButton.rx_enabled)
.addDisposableTo(disposeBag)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With