Code cracker
Code cracker

Reputation: 3166

if else condition in RXSwift

There is a textfield with validation using RXSwift. I want to disable validation based on switch action.

 // Start Time
 startTimeValid = startTimeTextfield.rx.text.orEmpty.map{
            $0.count > 0
  }

 // End time
 endTimeValid = endTimeTextfield.rx.text.orEmpty.map{
            $0.count > 0
 }

 everythingValid = Observable.combineLatest(startTimeValid,endTimeValid){ $0 && $1 }
        

 endTimeValid.bind(to: endTimeErrorLabel.rx.isHidden).disposed(by: bag)
 startTimeValid.bind(to: startTimeErrorLabel.rx.isHidden).disposed(by: bag)
 everythingValid.bind(to: createButton.rx.isEnabled).disposed(by: bag)

        
 createButton.rx.tap.subscribe(onNext:{

            print("success")

        }).disposed(by: bag)

so in above code End time and start time textfields both are being validated. Based on boolean i need to disable validation for EndTime Textfield.

The code i tried:

 @objc func endDateRequired(_ aSwitch : UISwitch){

        
        if aSwitch.isOn{

            everythingValid = Observable.combineLatest(eventTitleValid, startDateValid, endDateValid){ $0 && $1 && $2
            }
            everythingValid.bind(to: createButton.rx.isEnabled).disposed(by: bag)
       
        }else{
            
            everythingValid = Observable.combineLatest(eventTitleValid, startDateValid, endDateValid, startTimeValid,endTimeValid){ $0 && $1 && $2 && $3 && $4
            }
            everythingValid.bind(to: createButton.rx.isEnabled).disposed(by: bag)

        }
        
    }

I am trying to make it simplified in reactive style.

Upvotes: 1

Views: 712

Answers (2)

matt
matt

Reputation: 535989

I do not know RxSwift but I can see that the problem is that a line like if aSwitch.isOn is not reactive. You need to observe the switch, too, and take all of the values into account.

Here's a Combine example, which no doubt translates in some simple way into RxSwift. We have two text fields, a switch, and a button. The button is to be enabled only if both text field have content, unless the switch is turned off in which case the button is just enabled willy-nilly (no validation):

class ViewController: UIViewController {
    @IBOutlet weak var tf1: UITextField!
    @IBOutlet weak var tf2: UITextField!
    @IBOutlet weak var sw: UISwitch!
    @IBOutlet weak var button: UIButton!
    var storage = Set<AnyCancellable>()
    override func viewDidLoad() {
        super.viewDidLoad()
        let tfpub1 = tf1.publisher(for:.editingChanged)
            .map {$0.text ?? ""}
            .prepend("")
        let tfpub2 = tf2.publisher(for:.editingChanged)
            .map {$0.text ?? ""}
            .prepend("")
        let swpub = sw.publisher()
            .map {$0.isOn}
            .prepend(true)
        tfpub1.combineLatest(tfpub2, swpub)
            .map { !$2 || ( $0.count > 0 && $1.count > 0 ) }
            .assign(to: \.isEnabled, on: self.button)
            .store(in: &storage)
    }
}

For the UIControl publisher method, see my https://www.apeth.com/UnderstandingCombine/publishers/publisherscustom.html

Upvotes: 2

Daniel T.
Daniel T.

Reputation: 33979

@matt has the right answer but the solution is simpler in RxSwift because of the global combineLatest operator that can take up to 8 parameters...

Observable.combineLatest(
    startTimeTextField.rx.text.orEmpty,
    endTimeTextField.rx.text.orEmpty,
    endDateRequired.rx.isOn
)
{ startTime, endTime, endDateRequired in
    !startTime.isEmpty && (!endTime.isEmpty || !endDateRequired)
}
.bind(to: createButton.rx.isEnabled)
.disposed(by: disposeBag)

Upvotes: 3

Related Questions