角度形式的异步验证问题

时间:2021-03-22 22:01:04

标签: angular typescript

我想分两步验证一个名为“name”的字段,首先是同步,然后是异步检查“name”是否在表单提交之后使用。

app.component.html

<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
  <input type="text" formControlName="name"/>
  <div *ngIf="name?.invalid && (name?.dirty || name?.touched)">
    <div *ngIf="name?.errors?.maxlength">
      Max error
    </div>
  </div>
  <div *ngIf="myForm?.errors?.hasTaken">
    This name is already taken
  </div>
  <button type="submit">Go</button>
</form>

app.component.ts

import { Component, Injectable } from '@angular/core';
import {AbstractControl, AsyncValidator, FormControl, FormGroup, ValidationErrors, Validators} from '@angular/forms';
import {combineLatest, from, Observable, of} from 'rxjs';
import {map} from 'rxjs/operators';


// simulation of validation
function UniqueNameValidator(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
  let promise = new Promise<ValidationErrors | null>((resolve, reject) => {
    const nameControl = control.get('name');
    if (nameControl?.value === 'ok') {
      setTimeout(() => resolve(null), 1000)
    } else {
      setTimeout(() => resolve({
        hasTaken: true
      }), 1000)
    }
  })
  return promise;
}


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  myForm = new FormGroup({
    name: new FormControl('', {
      validators: Validators.maxLength(10),
    })
  }, {
    asyncValidators: UniqueNameValidator,
    updateOn: 'submit'
  });

  onSubmit() {
    console.log(this.myForm)
  }

  get name() { return this.myForm.get('name'); }
}

但是我得到的是调用异步验证,即使我在输入中没有输入任何内容并且没有按下按钮。

extrange behaviour

如何修复此行为并同步验证,然后在提交后使用异步验证?

1 个答案:

答案 0 :(得分:0)

在调用您的承诺之前检查输入字符串的长度

function UniqueNameValidator(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
  if(nameControl?.value.length < 10){
    return Promise.resolve()
  }
  let promise = new Promise<ValidationErrors | null>((resolve, reject) => {
    const nameControl = control.get('name');
    if (nameControl?.value === 'ok') {
      setTimeout(() => resolve(null), 1000)
    } else {
      setTimeout(() => resolve({
        hasTaken: true
      }), 1000)
    }
  })
  return promise;
}

看起来您正在调用表单上的验证器而不是输入。我更喜欢[form builder][1],但是...

// with FB injected as fb
const form = this.fb.group({name:[null, [Validators.max(10)], [UniqueNameValidator] ]})

作为奖励,您可以将最小长度值传递给验证器。您可以通过将 UniqueNameValidator 包装在一个函数中来做到这一点。您可以将其称为 UniqueNameValidatorWrapper(10)