簡體   English   中英

當有多個 AsyncValidator 時,Angular FormBuilder 處於 Pending 狀態

[英]Angular FormBuilder in Pending state when having more than one AsyncValidator

我正在嘗試向我的 Angular 表單添加一些自定義驗證。 問題是,當表單中只有一個 AsyncValidator 時,一切都按預期工作,所以我更改了一個值,表單狀態更改為Valid 而當我有兩個 AsyncValidator 時,表單將保持Pending狀態,直到我更改它們。

這是我的代碼:

uniqueValue.validator.ts

export function UniqueValidator(service: ExistsService, originalValue: string = null): AsyncValidatorFn {
    return control => {
        if (control.valueChanges == null) {
            return of(null);
        }

        return control.valueChanges
            .pipe(
                debounceTime(400),
                distinctUntilChanged(),
                switchMap(value => {
                    if (value === originalValue) {
                        control.markAsPristine();
                        return of(false);
                    }

                    return service.exists(value);
                }),
                map((unique: boolean) => (!unique ? null : { 'notUnique': true })),
                first());
    }
}

some-component.component.ts

ngOnInit() {
  this.form= this.fb.group({
    email: [this.email,
      [Validators.required],
      UniqueValidator(this.myService)
    ],
    username: [this.userName,
      [Validators.required],
      UniqueValidator(this.myService)
    ],
    fullName: [this.fullName]
  });

  this.form.markAsPristine();
}

submitButtonEnabled(): boolean {
  return this.form.valid
    && this.form.dirty;
}

ps 這是一個Edit Form ,因此所有字段的初始狀態總會有值。 因此,當表單第一次加載時,兩個字段(電子郵件和用戶名)都是有效的,並且其中一個更改將觸發 AsyncValidator,如果響應為真,則submitButtonEnabled應返回真。

AsyncValidator 比您的代碼更容易一些。 (真的你不能使用 valueChanges 可觀察的)。

想象一下,你有一個帶有兩個函數的 dataService,如果存在則返回一個可觀察的 true,如果不存在則返回 false。 好吧,我使用“of” rxjs 運算符和延遲進行模擬

export class DataService {

  constructor() { }
  emails=['qqq@qqq.com','aaa@aaa.com']
  userNames=['qqq','aaa','bbb']
  existEmail(email:string)
  {
   return of(this.emails.indexOf(email)>=0?true:false).pipe(delay (1000))
  }
  existUser(userName:string)
  {
   return of(this.userNames.indexOf(userName)>=0?true:false).pipe(delay (1000))
  }
}

你可以創建一個像

form=new FormGroup( {
    name:new FormControl('',{asyncValidators:this.uniqueName(),updateOn:'blur'}),
    email:new FormControl('',{asyncValidators:this.uniqueEmail(),updateOn:'blur'}),
  })
  uniqueName()
  {
    return (control:FormControl)=>{
       return this.dataService.existUser(control.value).pipe(map(x=>
       {
         return x?{error:'yet exist'}:null
       }))
    }
  }
  uniqueEmail()
  {
    return (control:FormControl)=>{
       return this.dataService.existEmail(control.value).pipe(map(x=>
       {
         return x?{error:'yet exist'}:null
       }))
    }
  }

查看堆棧閃電戰

考慮到:

  1. 我使用 {updateOn:'blur'} 只檢查何時模糊
  2. 驗證器返回一個 Observable,如果出現錯誤,則返回一個對象 {error:'yet exist'} 的 observable,如果有效則返回一個 observable 為 null。
  3. 從 dataService 您收到 true -if existing- 或 false -if not- 我使用 (pipe(map) 來轉換響應,並使用 'of' rxjs 返回可觀察的

如果你想使用延遲,因為你不喜歡 {updateOn:'blur'} 我建議使用 tro auxiliars formControls

control1=new FormControl()
control2=new formControl()
form=new FormGroup( {
        name:new FormControl('',{asyncValidators:this.uniqueName()}),
        email:new FormControl('',{asyncValidators:this.uniqueEmail()}),
      })

this.control1.valueChanges.pipe(
      debounceTime(400),
      distinctUntilChanged()).subscribe(res=>{
          this.form.get('name').setValue(res)
      })

this.control2.valueChanges.pipe(
      debounceTime(400),
      distinctUntilChanged()).subscribe(res=>{
          this.form.get('email').setValue(res)
      })

你不使用表格,你使用

<input [formControl]="control1">
<input [formControl]="control2">

嘗試這個:

  if (!control.valueChanges) {
    return of(null as ValidationErrors);
  }

  if (!obs) {
    obs =  merge(
      of(control.value),
      control.valueChanges
    ).pipe(
      debounceTime(500),
      distinctUntilChanged(),
      switchMap((login: string) => {
        ...
      }),
      map(_ => {
        return id == null ?
          null :
          { exists: true };
      })
    );
  }

  return obs.pipe(first());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM