我想在点击按钮时检查文本是否有效

时间:2019-04-19 09:48:47

标签: rx-swift

我想在点击按钮时检查文本是否有效。如果验证失败,它将在UILabel上显示错误文本,并且不发送请求。否则,如果验证成功,它将发送请求。

我看到了很多有关登录的演示,但是它们控制了按钮的启用,以避免在点击按钮时验证数据。我对此感到困惑。

我已经写了一些代码。

class LoginViewModel: BaseViewModel, ViewModelType {
    struct Input {
        let loginTaps: Driver<Void>
    }
    struct Output {
        let validatedUsername: Driver<Bool>
        let validatedPassword: Driver<Bool>
    }

    let username = BehaviorRelay(value: "")
    let password = BehaviorRelay(value: "")
    let loginTapped = PublishSubject<Void>()

    func transform(input: Input) -> Output {

        let validatedUsername = username.asDriver(onErrorJustReturn: "").map { username in
            return username.isPhoneNumber
        }

        let validatedPassword = password.asDriver(onErrorJustReturn: "").map { password in
            return password.count > 7
        }

        input.loginTaps.map { () -> Void in
            <#code#>
            // I want do check and then do network request
        }

        input.loginTaps.drive(onNext: { [weak self] () in
                self?.loginTapped.onNext(())
            }).disposed(by: rx.disposeBag)

        loginTapped.flatMapLatest { _  -> Observable<RxSwift.Event<Token>> in

           // and if I want to return Bool not Token, how should I do????????????

            return self.provider.login(username: self.username.value, password: self.password.value)
                .asObservable()
                .materialize()
            }.subscribe(onNext: { (event) in
                switch event {
                case .next(let token):
                    AuthManager.setToken(token: token)
                case .error(let error):
                    log.error(error.localizedDescription)
                default: break
                }
            }).disposed(by: rx.disposeBag)

        return Output(validatedUsername: validatedUsername,
                      validatedPassword: validatedPassword)
    }
}

1 个答案:

答案 0 :(得分:0)

我希望看到这样的东西:

class LoginViewModel {
    struct Input {
        let loginTap: Signal<Void>
        let username: Driver<String>
        let password: Driver<String>
    }

    struct Output {
        let errorText: Driver<String>
        let loginSuccess: Signal<Void>
    }

    var networkRequest: (URLRequest) -> Observable<Data> = { _ in fatalError("need to replace this with an implementation.") }

    func transform(input: Input) -> Output {

        func isValidCredentials(username: String, password: String) -> Bool {
            return username.isPhoneNumber && password.count > 7
        }

        let credentials = Driver.combineLatest(input.username, input.password)

        // this chain emits when the login button is tapped and the credentials are invalid
        let invalidInputError = input.loginTap
            .withLatestFrom(credentials)
            .filter { !isValidCredentials(username: $0, password: $1) }
            .map { _ in "Credentials are invalid" }
            .asDriver(onErrorRecover: { _ in fatalError("can't get here") })

        let networkRequest = self.networkRequest // to avoid dealing with `self` in the flatMap below

        // this chain makes a request if the login button is tapped while the credentials are valid
        let loginResult = input.loginTap
            .withLatestFrom(credentials)
            .filter { isValidCredentials(username: $0, password: $1) }
            .map { URLRequest.login(username: $0, password: $1) }
            .asObservable()
            .flatMapLatest { networkRequest($0).materialize() }
            .share(replay: 1)

        // this chain emits when the login result produces an error
        let loginError = loginResult
            .map { $0.error }
            .filter { $0 != nil }
            .map { $0!.localizedDescription }
            .asDriver(onErrorRecover: { _ in fatalError("can't get here") })

        // this chain emits when the login result succeeds
        let loginSuccess = loginResult
            .filter { $0.element != nil }
            .map { _ in }
            .asSignal(onErrorRecover: { _ in fatalError("can't get here") })

        let errorText = Driver.merge(invalidInputError, loginError)

        return Output(errorText: errorText, loginSuccess: loginSuccess)
    }
}