【问题标题】:Angular async validation not printing error message角度异步验证不打印错误消息
【发布时间】:2019-12-11 06:30:26
【问题描述】:

下面是我的组件:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpService } from './http.service';
import { ProjectidService } from './projectid.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
 projectDetailForm: FormGroup;
  public submitted = false;
  constructor(private fb: FormBuilder, private projectidvalidator: ProjectidService) { }

  ngOnInit() {
    this.projectDetailForm = this.fb.group({
      projectid: ['', [Validators.required], [this.projectidvalidator.validate.bind(this.projectidvalidator)]],
      projectname: ['name', Validators.required]
    })
  }
  get f() { return this.projectDetailForm.controls; }

  get validprojectid() { return this.projectDetailForm.get('projectid'); }

  onSubmit(form: FormGroup) {
    this.submitted = true;

    // stop here if form is invalid
    if (this.projectDetailForm.invalid) {
      return;
    }
    console.log('Valid?', this.projectDetailForm.valid); // true or false
    console.log('ID', this.projectDetailForm.value.projectid);
    console.log('Name', this.projectDetailForm.value.projectname);
  }

}

我的服务:

import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { delay, tap, debounceTime } from 'rxjs/operators';
@Injectable()
export class HttpService {

  constructor() { }

  checkProjectID(id): Observable<any> {
     // Here I will have valid HTTP service call to check the data

     return of(true)
  }
}

我的异步验证器:

import { HttpService } from './http.service';
import { Injectable } from '@angular/core';
import { AsyncValidator, AbstractControl, ValidationErrors } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { map, catchError, debounceTime, switchMap } from 'rxjs/operators';
@Injectable()
export class ProjectidService {

  constructor(private _httpService:HttpService) { }


    validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
        console.log(control.value);

        return control.valueChanges.pipe(
            debounceTime(500),
            switchMap(_ => this._httpService.checkProjectID(control.value).pipe(
                map(isTaken => {
                    console.log(isTaken);
                    if (isTaken) {
                        return { noproject: true }
                    } else {
                        return null
                    }

                })
            )),
            catchError(() => null)
        );


    }

}

和模板:

<form [formGroup]="projectDetailForm" name="projectdetails" (ngSubmit)="onSubmit(projectDetailForm)">
    <div class="form-group">
        <label for="id">Project ID</label>
        <input type="text" class="form-control" id="id" [ngClass]="{ 'is-invalid': f.projectid.invalid && (f.projectid.dirty || f.projectid.touched) }" placeholder="Project ID" name="projectid" formControlName='projectid'>
        <button type="button">Validate</button>
        <div *ngIf="f.projectid.invalid && (f.projectid.dirty || f.projectid.touched)" class="invalid-feedback">
            <div *ngIf="f.projectid.errors.required">Project ID is required</div>
            <div *ngIf="f.projectid.errors?.noproject">
                Project id is not valid
            </div>
        </div>
        <div *ngIf="f.projectid.errors?.noproject">
            Project id is not valid
        </div>
        {{f.projectid.errors | json}}
    </div>
    <div class="form-group">
        <label for="name">Project Name</label>
        <input type="text" class="form-control" id="name" placeholder="Project Name" name="projectname" readonly formControlName='projectname'>
    </div>
    <div class="form-group d-flex justify-content-end">
        <div class="">
            <button type="button" class="btn btn-primary">Cancel</button>
            <button type="submit" class="btn btn-primary ml-1">Next</button>
        </div>
    </div>
</form>

问题是我的自定义async 验证错误消息未显示。

这里是stackblitz 示例

【问题讨论】:

    标签: javascript angular typescript


    【解决方案1】:

    您可以使用rxjs/timer

    import { timer } from "rxjs";
    ....
        return timer(500).pipe(
          switchMap(() => {
            if (!control.value) {
              return of(null);
            }
            return this._httpService.checkProjectID(control.value).pipe(
              map(isTaken => {
                console.log(isTaken);
                if (isTaken) {
                  return { noproject: true };
                } else {
                  return null;
                }
              })
            );
          })
        );
    

    Sample

    【讨论】:

    • shreyas 为什么它不使用 debouceTime 和使用 control.valueChange ?有什么具体原因吗?
    • 我觉得你的做法和this解释不谋而合
    • 当调用时间超过 500 毫秒时,此代码将无法按预期工作。
    【解决方案2】:

    真正的问题是我自己也遇到过,你订阅了值的变化,但你需要等待状态变化返回。 它在通话时处于“待处理”状态。 debounce/timer/... 只是“hacks”,因为你永远不知道什么时候返回值。

    声明一个变量:

    this.formValueAndStatusSubscription: Subscription;
    

    在你的

    this.formValueAndStatusSubscription =
      combineLatest([this.form.valueChanges, this.form.statusChanges]).subscribe(
        () => this.formStatusBaseOnValueAndStatusChanges = this.form.status
      );
    

    别忘了销毁订阅

    【讨论】:

      【解决方案3】:

      异步验证中最重要的一点如 Angular Doc 中所述

      返回的 observable 必须是有限的,这意味着它必须在 一点。要将无限的 observable 转换为有限的 observable,请使用管道 通过过滤运算符(例如 first、last、take、 或采取Until。

      所以基本上你可以使用例如 take(1) ,它会先发射然后标记 Observable completed

       return control.valueChanges.pipe(
        debounceTime(500),
        take(1),
        switchMap(() =>
          this._httpService.checkProjectID(control.value).pipe(
            map(isTaken =>
              isTaken ? { noproject: true } : null
            )
          ))
      )
      

      demo

      【讨论】:

      • 有什么方法可以实现debounceTimedistinctUntilChange
      • 我去看看
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-11
      • 2017-12-26
      • 2019-08-14
      • 1970-01-01
      • 1970-01-01
      • 2020-11-04
      • 2022-06-10
      相关资源
      最近更新 更多