使用 RxSwift 和 RXCocoa 验证按钮单击时的所有文本字段

Posted

技术标签:

【中文标题】使用 RxSwift 和 RXCocoa 验证按钮单击时的所有文本字段【英文标题】:Validate all textfield on button click using RxSwift and RXCocoa 【发布时间】:2018-03-29 09:55:11 【问题描述】:

我是 RxSwift 和 RxCocoa 的新手,我正在学习它。

我想验证按钮单击时的所有文本字段,并根据验证向用户显示警报消息。

验证成功后,我需要在表中插入记录。

参考以下代码...

var result = txtFname.rx.text
    result.asObservable().subscribe(onNext:  text in
        if text!.isEmpty 
            self.showAlert(msg: "Plese enter first name.")
            self.txtFname.becomeFirstResponder()
        
    ).disposed(by: disposeBag)

    result = txtLname.rx.text
    result.asObservable().subscribe(onNext:  text in
        if text!.isEmpty 
            self.showAlert(msg: "Please enter last name.")
            self.txtLname.becomeFirstResponder()
        
    ).disposed(by: disposeBag)

    result = txtEmail.rx.text
    result.asObservable().subscribe(onNext:  text in

        if text!.isEmpty 
            self.showAlert(msg: "Please enter email id.")
            self.txtLname.becomeFirstResponder()
        
    ).disposed(by: disposeBag)

   //need to check here if all fields are valid or not 
   //if all fields are valid then insert record....

当我按下一个按钮时,它会同时检查所有验证并显示警报...

但我想这样做,如果一个验证失败,那么在之前的验证成功之前它不应该更进一步......

我不知道如何实现这一点。任何帮助将不胜感激。

【问题讨论】:

看一次可能对你有帮助***.com/questions/42860384/… 已经看过了,这不是我想要做的......它实际上会根据结果禁用一个按钮......我不想这样做......我想要按钮将始终启用,单击按钮时我想检查验证。 【参考方案1】:

你可以做这样的事情。

  self.button.rx.tap.asObservable()
     .filter( (_) -> Bool in
        guard !(self.txtFname.text ?? "").isEmpty else 
           self.showAlert(msg: "Please enter first name.")
           self.txtFname.becomeFirstResponder()
           return false
        

        guard !(self.txtLname.text ?? "").isEmpty else 
           self.showAlert(msg: "Please enter last name.")
           self.txtLname.becomeFirstResponder()
           return false
        

        guard !(self.txtEmail.text ?? "").isEmpty else 
           self.showAlert(msg: "Please enter email id.")
           self.txtEmail.becomeFirstResponder()
           return false
        

        return true
     )
     .subscribe  _ in
        // do something when all the fields are valid
        self.showAlert(msg: "All fields are valid")
     
     .disposed(by: disposeBag)

【讨论】:

是的......我知道,但我想以响应式的方式来做,比如 txtField.text.rx......然后 doSomething()...... 您的事件序列是通过点击按钮触发的,而不是在文本更改时触发。 hmmm...所以你的意思是不可能在按钮点击事件上观察文本字段的文本? 您可以使用“map”将按钮点击转换为文本 - self.button.rx.tap.map return self.txtFname.text . 如何通过流的反应方式来完成。 txtFname.text 不完全是被动的。【参考方案2】:

这不是完全相同的答案,但您可以实现这样的目标。

      class DataValidator 
            class func validName(name:String) -> Bool 
            if let regex =
            try? NSRegularExpression(pattern: "^\\w+( \\w+\\.?)*$", options:
            .CaseInsensitive) 
            return name.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) > 2 &&
            regex!.matchesInString(name, options: NSMatchingOptions.ReportProgress, range: NSMakeRange(0,
            name.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))).count > 0 
            return false 

            class func validEmail(email:String) -> Bool if let regex =
            try? NSRegularExpression(pattern: "^\\S+@\\S+\\.\\S+$", options: .CaseInsensitive)
            return regex!.matchesInString(email, options: NSMatchingOptions.ReportProgress, range: NSMakeRange(0,
            email.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))).count > 0 
        return false 
 

// end of validator class

您可以使用以下内容:

let nameSignal:RACSignal = nameTextField.rac_textSignal().map  (text) -> AnyObject! in
return DataValidator.validName(text as! String) 
let emailSignal = emailTextField.rac_textSignal().map  (text) -> AnyObject! in
return DataValidator.validEmail(text as! String) 

RACSignal.combineLatest([nameSignal, emailSignal]).subscribeNext  (valid) -> Void in
   self.button.enabled = valid as! Bool

【讨论】:

【参考方案3】:
class Validator 

    class func validEmail(email:String) -> Bool 
        if let regex = try? NSRegularExpression(pattern: "^\\S+@\\S+\\.\\S+$", options: .caseInsensitive)
        return regex.matches(in: email, options: NSRegularExpression.MatchingOptions.reportProgress, range: NSMakeRange(0,                                                                                                                        email.lengthOfBytes(using: String.Encoding.utf8))).count > 0 
        return false
    

那么你可以如下使用它:

var isValid : Observable<Bool>
    return Observable.combineLatest(username.asObservable())
     (username) in
        return Validator.validEmail(email: username)
    

【讨论】:

我试过这个,我得到参数类型 '(String) -> Bool' 不符合预期的类型 'Observable Type' 我试试这个,我得到同样的错误。 @htjohn 。你的解决方案是什么?

以上是关于使用 RxSwift 和 RXCocoa 验证按钮单击时的所有文本字段的主要内容,如果未能解决你的问题,请参考以下文章

Swft3 (RxSwift, RxCocoa) - TableView 使用响应式编程展开和折叠概念

将 SwiftUI 按钮绑定到 AnySubscriber,例如 RxCocoa 的按钮点击

处理 UITableView 绑定中的连接错误(Moya、RxSwift、RxCocoa)

RxSwift 使用 RxCocoa 绑定到动画

如何在 UITableView 的 RXswift 和 RXCocoa 中实现 tableview 单元格的内部?

关于 RxSwift/RxCocoa 与 combineLatest 绑定的问题