You can turn the taps on the UIButton in the Observable and pass it to the ViewModel along with two observables from the UITextFields.
This is a small working example for your scenario. (I used a small mk client class to simulate a service response):
ViewController:
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { let loginTxtField = UITextField(frame: CGRect(x: 20, y: 50, width: 200, height: 40)) let passwordTxtField = UITextField(frame: CGRect(x: 20, y: 110, width: 200, height: 40)) let loginButton = UIButton(type: .RoundedRect) let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1) loginTxtField.backgroundColor = UIColor.whiteColor() view.addSubview(loginTxtField) passwordTxtField.backgroundColor = UIColor.whiteColor() view.addSubview(passwordTxtField) loginButton.setTitle("Login", forState: .Normal) loginButton.backgroundColor = UIColor.whiteColor() loginButton.frame = CGRect(x: 20, y: 200, width: 200, height: 40) view.addSubview(loginButton)
These are two interesting parts:
// 1: We insert three Observables into the ViewModel when we initialize it.
// 2: Then we subscribe to the ViewModel output to get the Auth model after the login has been completed.
ViewModel:
import RxSwift struct Auth { let token: String } struct AuthResponse { let token: String } class ViewModel { // Output let authResponse: Observable<Auth> init(withLogin login: Observable<String>, password: Observable<String>, didPressButton: Observable<Void>) { let mockAuthService = MockAuthService() // 1 let userInputs = Observable.combineLatest(login, password) { (login, password) -> (String, String) in return (login, password) } // 2 authResponse = didPressButton .withLatestFrom(userInputs) .flatMap { (login, password) in return mockAuthService.getAuthToken(withLogin: login, mergedHash: password) } .map { authResponse in return Auth(token: authResponse.token) } } } class MockAuthService { func getAuthToken(withLogin login: String, mergedHash: String) -> Observable<AuthResponse> { let dummyAuthResponse = AuthResponse(token: "dummyToken->login:\(login), password:\(mergedHash)") return Observable.just(dummyAuthResponse) } }
ViewModel receives 3 Observables in its init method and hooks them to its output:
// 1: Combine the last value of the input text field and the last value of the password text field in one observation.
// 2: When the user clicks the button, use the last value of the text input field and the last value of the password text field and pass this to the auth service using flatMap . When the auth client returns AuthResponse , map this to the Auth model. Set the result of this chain as the output of the AuthResponse ViewModel