具有值更改的异步验证器

时间:2017-02-27 18:53:49

标签: angular rxjs angular-material2

如果用户输入的输入与列表中的项匹配,我想检查带有异步验证器的自动完成小部件。

如果用户输入的值与已过滤列表中的项匹配,则其有效,否则无效。

伪代码中的示例(状态/过滤将来自异步API):

states: ['Michigan', 'Minnesota', 'Mississippi']

user input 'mi':
filteredStates: ['Michigan', 'Minnesota', 'Mississippi'] -> invalid because 'mi' does not match excact any value

user input 'Michigan':
filteredStates: ['Michigan'] -> valid because we have an excact match

使用Async Validator是因为我想重用我正在使用的observable来对值的变化做出反应并根据我得到的值过滤掉项目。

使用过滤值进行观察:

this.stateCtrl = new FormControl('', [], this.stateExists());
this.filteredStates = this.stateCtrl.valueChanges
    .startWith(null)
    .map(name => this.filterStates(name));

异步验证器:

stateExists(states): AsyncValidatorFn  {
return (control: AbstractControl): Observable<any> => {
  if(!control.dirty || !control.value || control.value.length === 0) return Observable.of(null);

  return this.filteredStates
    .switchMap(states => Observable.from(states))
    .filter(state => state === control.value)
    .do(() => console.log('state matches value'))
    .map(() => null)
}

}

Plnkr: http://plnkr.co/edit/vxkbS8Icg7crUGIyfAQK?p=preview (实际上我的价值观来自API)

我有两个问题:

  1. 我无法在验证器中传递可观察的过滤状态,因为此时它不存在。现在,每次验证器运行时,它都会获得一个新的observable,并且会在调用验证器时调用它。

  2. 如果值匹配,我的验证器会过滤掉,但我如何更改代码以映射对象,例如{notFound:true}如果我找不到值,如果找到值则为null?在我的例子中,它将永远不会被过滤掉。

1 个答案:

答案 0 :(得分:1)

我认为您混淆了异步验证器异步字段值:您的字段可能异步获取其值,但它并不代表验证器也应该是异步的。

验证程序并不关心值是来自异步HTTP调用还是来自键入字段的用户。当它执行其验证工作时,该值存在(它是&#34;同步&#34;如果你愿意的话)。

因此,您可以按如下方式简化代码:

// Attach a SYNCHRONOUS validator to the field.
this.stateCtrl = new FormControl('', this.stateExistsSync('California'));

// Declare the synchronous validator.
stateExistsSync(validState: string): ValidatorFn {
  return (control: AbstractControl) => {
    return control.value && control.value != validState ? { stateMismatch: true } : null;
  };
}

Plunkr:http://plnkr.co/edit/1WSueXS1oBBmgfh5OCuN?p=preview

请注意,验证器接受validState作为参数。

仅供参考,当验证本身触发异步操作时,使用异步验证器,例如,用于验证用户名是否已被使用的HTTP请求。