Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 表单控件异步验证问题_Angular_Observable_Angular2 Observables - Fatal编程技术网

Angular 表单控件异步验证问题

Angular 表单控件异步验证问题,angular,observable,angular2-observables,Angular,Observable,Angular2 Observables,我试图在Angular2上实现一个异步验证,但是当我出于某种原因试图输入一些东西时,去抖动不起作用。它会根据我的输入触发多次。此外,在加载时,将触发我的异步验证器,从而将状态设置为“挂起”,以便信息框显示正在检查… 下面是我如何实现它的: HTML: 异步验证代码: couponAsyncValidation(control: FormControl): Promise<any | null> | Observable<any | null> { return

我试图在Angular2上实现一个异步验证,但是当我出于某种原因试图输入一些东西时,去抖动不起作用。它会根据我的输入触发多次。此外,在加载时,将触发我的异步验证器,从而将状态设置为“挂起”,以便信息框显示
正在检查…

下面是我如何实现它的:

HTML:

异步验证代码:

 couponAsyncValidation(control: FormControl): Promise<any | null> | Observable<any | null> {
     return new Promise( (res, rej) => {
      control.valueChanges.pipe(
        debounceTime(2000),
        distinctUntilChanged(),
        switchMap(value => this.userService.couponChecker(value)),
        map( (q) => q ),
        first()
      ).subscribe(
        (d) => { 
        console.log(d)
         d.is_coupon_valid ? res(null) : res({invalid: true})
        }
      )
    })
  }

我有一个类似的情况,除了我的异步验证器直接在表单上。。。代码如下所示,但与您的需要不完全匹配。。我怀疑您的核心问题是,您对控件值的订阅发生了更改,这是您不需要做的,因为将其设置为验证器应该已经导致在值更改时调用该验证器

validateExists(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
{
    return timer(500).pipe(
            switchMap(() =>
                this.service.checkThingExists(control.value.value1, control.value.value2).pipe(
                    tap(() => setTimeout(() => this.isValid.emit(this.form.get('parcel').valid))),
                    map(valid => (valid ? null : { notFound: true }))
                )
            )
        );
}
validateExists(控件:AbstractControl):承诺|可观察{
{
返回计时器(500)。管道(
开关映射(()=>
this.service.checkThingExists(control.value.value1,control.value.value2)。管道(
点击(()=>setTimeout(()=>this.isValid.emit(this.form.get('packet').valid)),
映射(valid=>(valid?null:{notFound:true}))
)
)
);
}

我有一个类似的情况,除了我的异步验证器直接在表单上…下面是代码,但它不会完全符合您的需要。我怀疑您的核心问题是,您订阅的控制值发生了更改,而您不需要这样做,因为将其设置为验证器应该已经导致该更改生效无论值何时更改,都要调用dator

validateExists(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
{
    return timer(500).pipe(
            switchMap(() =>
                this.service.checkThingExists(control.value.value1, control.value.value2).pipe(
                    tap(() => setTimeout(() => this.isValid.emit(this.form.get('parcel').valid))),
                    map(valid => (valid ? null : { notFound: true }))
                )
            )
        );
}
validateExists(控件:AbstractControl):承诺|可观察{
{
返回计时器(500)。管道(
开关映射(()=>
this.service.checkThingExists(control.value.value1,control.value.value2)。管道(
点击(()=>setTimeout(()=>this.isValid.emit(this.form.get('packet').valid)),
映射(valid=>(valid?null:{notFound:true}))
)
)
);
}

异步验证器在每次值更改时都会被调用。因此,每次值更改时,您都会创建一个新的observable并订阅它。每次值更改时,这个observable都会发出信号。@jbnize我还不知道。如果我的问题不清楚,很抱歉。但是为什么会发生这种情况,即使我设置了
去BounceTime
在设置的时间过去之前阻止它施放EDI错过了对first()的调用。每次值更改时都会调用异步验证器。因此,每次值更改时,您都会创建一个新的observable并订阅它。每次值更改时,该observable都会发出信号。@jbnize我已经知道了。如果我的问题不清楚,很抱歉。但为什么会发生这种情况,即使我设置了
debounceTime
我错过了对first()的调用。如果我不使用管道传输值更改,那么在用户键入时,您将如何从用户处获取值或输入?验证函数的输入参数具有具有该值的控件。因此,您只需执行control.value。您的函数将在每次输入更改时被调用,因为您将其设置为验证程序。因此,您不需要添加任何值捕获值更改的另一层。我明白了。这是第一个解决方案。但由于这是异步验证,每次键盘点击或输入时,我都会调用http请求。因此,我尝试使用
valueChanges
,因为它是可观察的,所以我可以通过管道将其传输,并从rxjs添加一个debounceTime运算符,以防止重新请求在我上面发布的示例中,我使用的是计时器(500)为了实现类似的功能,我仍然不需要订阅valueChanges。Timer也是一个RxJs函数。如果我不使用管道传输值更改,那么在用户键入时,您将如何从用户处获取值或输入?验证函数的输入参数具有具有具有值的控件。因此,您只需执行control.value。您的函数是每次输入更改时都会被调用,因为您将其设置为验证器。因此,您不需要添加另一个捕获值更改的层。我明白了。这是第一个解决方案。但由于这是异步验证,因此每次键盘点击或输入时,我都会调用http请求。因此,我尝试使用
valueChanges
because它是一个可观察的,所以我可以通过管道从rxjs添加一个去BounceTime操作符,这样每次键盘被点击时它都会阻止请求。在我上面发布的示例中,我使用timer(500)来实现类似的功能,我仍然不需要订阅值更改。timer也是rxjs函数。

import { AbstractControl, AsyncValidatorFn } from '@angular/forms';
import { switchMap, map} from 'rxjs/operators';
import { UserService } from '../user/services/user.service';
import { Observable, timer, of } from 'rxjs';

export class AsyncValidator {
  static couponValidator(miliSec: number, service: UserService): AsyncValidatorFn {
    return (control: AbstractControl): Observable<any | null> => {
      return timer(miliSec).pipe(
        switchMap(() => {
          if ( control.value ) {
            return service.couponChecker(control.value);
          }
          // this one is needed because for some reason on loading, the signup page
          // will immediately trigger this async call which sends a request to the backend
          // even though user has not inputted anything.
          // then sets the status of the form to pending thus resulting to an invalid form
          return of({is_coupon_valid: true});
        }),
        map( (res) =>  res.is_coupon_valid ? null : res )
      );
    };
  }
}

validateExists(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
{
    return timer(500).pipe(
            switchMap(() =>
                this.service.checkThingExists(control.value.value1, control.value.value2).pipe(
                    tap(() => setTimeout(() => this.isValid.emit(this.form.get('parcel').valid))),
                    map(valid => (valid ? null : { notFound: true }))
                )
            )
        );
}