【问题标题】:Angular custom validator is not throwing an error when using subscribe in itAngular 自定义验证器在其中使用订阅时不会引发错误
【发布时间】:2023-03-16 20:35:01
【问题描述】:

我正在尝试创建自定义验证器,它需要点击两个端点来获取所需的数据,然后比较数据的属性,如果它们不相等,那么我想抛出一个错误。这是验证器。

 checkIfSalaIsFull(control: AbstractControl): {[salaIsFull: string] : boolean}{
    if(control.value !=null){
      this.salaService.findActiveCards(control.value).subscribe(karty=>{
        this.salaService.findSalaByNRSali(control.value).subscribe(sala =>{
          if(karty.length === sala.pojemnosc){
            console.log(karty.length);
            console.log(sala.pojemnosc);
            return {'salaIsFull' : true};
          }
        });
      });
    }
    return null;
  }

问题是即使 console.log 为显示的属性显示相同的值,也不会引发错误。

<div class="form-group">
    <label for="nr_sali">Numer sali</label>
    <select class="form-control" id="nr_sali" formControlName="nr_sali">
      <option *ngFor="let sala of sale" [value]="sala.nr_sali" >{{sala.nr_sali}} - {{sala.oddzial}}</option>

    </select>

    <span *ngIf="formAddKarta.get('nr_sali').errors?.salaIsFull"
          class="help-block text-danger">
          Sala jest pełna
    </span>
</div>

我的后端工作正常,我用邮递员检查了它。

这也是我正在使用的 FormGroup 的设置:

 this.formAddKarta = new FormGroup({
      data_przyjecia: new FormControl(null, [KartyListaComponent.checkIfDateIsLessThanToday.bind(this),
        Validators.required]),
      godzina_przyjecia: new FormControl(null,[Validators.required]),
      data_wypisu: new FormControl(null),
      nr_sali: new FormControl(null, [Validators.required,this.checkIfSalaIsFull.bind(this)]),
      pesel: new FormControl(this.pesel)
    });

我在 nr_sali FormControl 的 Validators 表中设置了这个自定义验证器。

编辑:

我尝试使用地图而不是订阅,但是它没有发送检索sala的请求,只发送检索karty的请求。

 checkIfSalaIsFull(control: AbstractControl): {[salaIsFull: string] : boolean}{
    if(control.value !=null){
      this.salaService.findActiveCards(control.value).subscribe(karty=>{
        this.salaService.findSalaByNRSali(control.value).pipe(map(sala =>{
          if(karty.length === sala.pojemnosc){
            console.log(karty.length);
            console.log(sala.pojemnosc);
            return {'salaIsFull' : true};
          }else{
            return null;
          }
        }));
      });
    }else{
      return null;
    }

  }

【问题讨论】:

  • 您需要使用 map 而不是 subscribe 并返回映射后的 observable。您还需要将其设置为异步验证器
  • 我是 Angular 的新手,你能举例说明如何做到这一点吗?老实说,我不知道如何使用地图。 @AluanHaddad
  • 你可以在这里找到关于地图的信息:angular.io/guide/rx-library#operators 基本上你想使用.map(sala=&gt;而不是subscribe(sala=&gt;
  • @Rinktacular,当我使用 .map(sala=> 时收到错误消息“‘Observable’类型上不存在属性‘地图’”
  • 确保在文件顶部使用这个:import { map } from 'rxjs/operators'

标签: angular rxjs angular-forms


【解决方案1】:
  1. 您需要使用异步验证器而不是验证器,因为您需要发送请求,并且您需要将您的函数作为第三个参数放入您的 formControl(作为异步验证器)
  2. 你的验证器函数应该是返回Observable&lt;ValidationErrors | null&gt; | Promise&lt;ValidationErrors | null&gt;
  3. 你需要使用switchMap and map而不是订阅

这里是代码示例

进口

import { map, switchMap } from "rxjs/operators";
import { Observable } from "rxjs/internal/observable";

异步验证器示例

  checkIfSalaIsFull(
    control: AbstractControl
  ): Observable<ValidationErrors | null> {
    if (control.value != null) {
      return this.salaService.findActiveCards(control.value).pipe(
        switchMap(karty => {
          return this.salaService.findSalaByNRSali(control.value).pipe(
            map(sala => {
                console.log(karty.length);
                console.log(sala.pojemnosc);
                return karty.length === sala.pojemnosc ? { salaIsFull: true } : null;

            })
          );
        })
      );
    }
    return null;
  }

表单实现示例

 this.formAddKarta = new FormGroup({
      data_przyjecia: new FormControl(null, [
KartyListaComponent.checkIfDateIsLessThanToday.bind(this),  /** <-- if this function send the request you need to change this one too */

        Validators.required]),
      godzina_przyjecia: new FormControl(null, [Validators.required] ),
      data_wypisu: new FormControl(null),
      nr_sali: new FormControl(null, 
[Validators.required],
 [this.checkIfSalaIsFull.bind(this)]),  /** <-- third argument of formControl is the async validators array */
      pesel: new FormControl(this.pesel)
    });

【讨论】:

    【解决方案2】:

    从我上面的 cmets 继续,您想使用地图而不是订阅。由于 Angular 6,rxjs(库映射来自)包装要求它的操作被包装在一个管道函数中,如下所示:

    import { map } from 'rxjs/operations'
    
    ...
    
    this.salaService.findSalaByNRSali(control.value).pipe(map(sala => { 
      // Do work
      // ...
    }));
    

    【讨论】:

    • 所以当我添加地图时,我可以在日志中看到 Angular 没有发送接收萨拉的请求。只发送请求接收卡蒂。我想发送两个请求。 @Rinktacular
    • 请看EDIT
    猜你喜欢
    • 2020-03-26
    • 2021-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-10
    • 1970-01-01
    相关资源
    最近更新 更多