带有异步 RxJS 调用的 Angular 响应式(Reactive)表单自定义验证器

标签 angular rxjs angular-reactive-forms

查看下面的更新

我意识到我的问题是我对 observables 和 RxJS 非常陌生。

我有一个像这样的自定义验证器:

export function ValidateFinalQty(service: MyService) {
    return (control: AbstractControl): { [key: string]: any } | null => {
        let qty = service.GetQty();
        if (control.value != qty) {
            return { FinalQuantityNotMatching: true };
        } else {
            return null;
        }
    };
}

GetQty 返回一个 RxJS Observable。 那么我该如何设置,以便我的同步验证器根据异步调用返回正确的值?我需要验证器的返回类型保持为 { [key: string]: any } | null .

我看到类似 qty = await service.GetQty().first().toPromise(); 的建议但随后我返回了一个 promise ,但我无法返回一个让验证器按照我的理解工作的 promise 。

我该如何处理这个问题?

来 self 的package.json :

"@angular/core": "7.1.0",
"@angular/forms": "7.1.0",
"rxjs": "6.3.3",
"rxjs-compat": "^6.4.0",

更新 2019 年 5 月 23 日尝试实现@Sachin 的答案。 我在 map 内的断点永远不会被击中。我没有收到任何控制台日志,即使我删除映射中的逻辑并返回 null,它仍然总是返回 invalid。对这里发生的事情非常困惑。我的服务实际上正在被调用,我已经确认了这一点。

有什么想法吗?

export class CustomAsyncValidator {
    static ValidateFinalQty(qtyService: FinalQtyService, brf: BatchRecordForm): AsyncValidatorFn {
        return (control: AbstractControl) => {
            return qtyService.postCalcFinalQuanity(brf)
                .pipe(
                    map((qty) => {
                        console.log("running qty validator. value:", qty);
                        if (control.value !== qty) {
                            return { FinalQuantityNotMatching: true };
                        } else {
                            return null;
                        }
                    }),
                    catchError((err) => {
                        console.log("Error in final quantity validator", err);
                        return null;
                    }),
                    finalize(() => console.log("finished"))
                );
        };
    }
}

更新 2019 年 6 月 7 日

在订阅日志记录中,我得到了正确的答案(null 或 { FinalQuantityNotMatching: true }),但我的表单控件仍然无效。我做错了什么?

验证器.ts

export class CustomAsyncValidator {
    static ValidateFinalQty(fqs: FinalQtyService, brf: BatchRecordForm) {
        return (control: AbstractControl) => {
            return fqs.postCalcFinalQuanity(brf).pipe(
                debounceTime(500),
                tap((action) => console.log("final qty", action)),
                tap((action) => console.log("control.value", control.value)),
                map(arr => (arr.Value !== `${control.value}`) ? { FinalQuantityNotMatching: true } : null)
            ).subscribe(x => console.log("subscribe output", x));
        };
    }
}

组件.ts

 this.noteForm.addControl(this.finalQtyFormControlName, new FormControl(this.noteSubModuleForm.Value,
        [Validators.required, CustomAsyncValidator.ValidateFinalQty(this.finalQtyService, this.embrService.batchRecordForm)]));

更新 6/7/2019 #2

已关注 https://www.youtube.com/watch?v=zeX5CtFqkXQ我能够制作一个基于指令的验证器,但如果您能够看到我在之前的更新中做错了什么,我仍然更喜欢在我的 ts 中使用验证器。

@指令({ 选择器:“[有效最终数量]”, 提供者:[{提供:NG_ASYNC_VALIDATORS,useExisting:ValidateFinalQtyDirective,multi:true}] })

export class ValidateFinalQtyDirective implements AsyncValidator {

    constructor(private fqs: FinalQtyService, private embrService: EmbrService) { }

    validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
        return this.fqs.postCalcFinalQuanity(this.embrService.batchRecordForm).pipe(
            tap(x => {
                console.log("final qty", x);
                console.log("control.value", control.value);
            }),
            map(arr => (arr.Value !== `${control.value}`) ? { FinalQuantityNotMatching: true } : null)
        );
    }

最佳答案

我有一个类似的Validator指令,让我根据你的代码进行调整:

看看它是否适合你

import { Directive } from '@angular/core';
import { NG_ASYNC_VALIDATORS, AsyncValidator, AbstractControl, ValidationErrors } from '@angular/forms';
import { MyService } from './MyService';
import { Observable,  of as observableOf} from 'rxjs';


@Directive({
  selector: '[qty-valid]',
  providers: [{provide: NG_ASYNC_VALIDATORS, useExisting: QuantityValidatorDirective , multi: true}]
})
export class QuantityValidatorDirective implements AsyncValidator {    
   constructor(private service : MyService ) { }

    validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {

        return new Promise((resolve, reject) => {                
                this.service.GetQty()
                    .subscribe( (qty: any) => {
                       if (control.value != qty) {
                          resolve({ FinalQuantityNotMatching: true })
                       } else {
                          resolve(null)
                       }

                },error => resolve(null));
        });
    }
}

关于带有异步 RxJS 调用的 Angular 响应式(Reactive)表单自定义验证器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56281409/

相关文章:

javascript - BaseResponseOptions angular2 处理全局错误

php - 如何使用现有的 angular2 项目创建 Electron 桌面应用程序

javascript - Angular 2无法读取null的属性 'x'

javascript - Typescript Angular HTTP 请求仅获取最后结果

Angular 垫选择表单控制

angular - 是否可以将响应式(Reactive)数组控件绑定(bind)到 ngx-datatable?

javascript - 如何使用@angular/http中的http发送post请求

javascript - 为什么 'toPromise()' 对我不起作用

rxjs - 如何计算未完成的 Observable<Observable> 排放量

html - Angular react 形式控制值只是用户类型?