Using RxSwift, How To Enable UIButton Based on Valid Text?

finneycanhelp picture finneycanhelp · Nov 30, 2015 · Viewed 8.1k times · Source

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.

Answer

fpillet picture fpillet · Nov 30, 2015

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