如何将异步验证器添加到CUSTOM字段?

时间:2017-03-06 17:37:16

标签: angular angular2-forms

有谁知道如何在自定义字段的类别中声明 ASYNC验证方法

现在我在validate()方法中有一个同步验证器

@Component({
  selector: 'my-field',
  template: `<p>Some markup</p>`,
  providers: [
    { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MyFieldComponent), multi: true },
    { provide: NG_VALIDATORS, useExisting: forwardRef(() => MyFieldComponent), multi: true }
  ]
})
export class MyFieldComponent implements ControlValueAccessor {

  validate(c: FormControl) {
    // return null or error
  }

  // Rest of the code omitted for brevity
  // writeValue(), registerOnChange()...
}

但即使我使用与上面相同的语法将NG_ASYNC_VALIDATORS添加到提供者,也不会让我声明类似validateAsync()方法的内容。

除非......两种类型的验证器都以validate()方法为目标,我需要在此方法中执行同步和异步验证并且返回一个大的可观察 em>(可能包装多个错误键)?我对此不太确定。

SIDE注意:我可以开始工作的是直接在提供商中声明异步验证器,与useValue内联,或者与useClass分开。但是我希望将作为组件类的方法useExisting

1 个答案:

答案 0 :(得分:5)

我不完全明白你的要求是什么,但我可以给你一些可能对你有帮助的想法。

让我们从实现ControlValueAccessorValidator(同步)的自定义字段开始:

@Component({
  selector: 'my-field',
  template: `<p>Some markup</p>`,
  providers: [
    { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MyFieldComponent), multi: true },
    { provide: NG_VALIDATORS, useExisting: forwardRef(() => MyFieldComponent), multi: true }
  ]
})
export class MyFieldComponent implements ControlValueAccessor, Validator {
  onChange = (_: any) => { };
  onTouched = () => { };

  constructor(private _renderer: Renderer, private _elementRef: ElementRef) { }

  writeValue(value: any): void {
    const normalizedValue = value == null ? '' : value;
    this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', normalizedValue);
  }

  registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
  registerOnTouched(fn: () => void): void { this.onTouched = fn; }

  validationResult: any;

  validate(c: FormControl) {
    this.validationResult = { 'sync': true };
    return null;
  }
}

在声明指令之后将实现AsyncValidator

@Directive({
  selector: 'my-field[formControlName],my-field[ngModel]',
  providers: [{
    provide: NG_ASYNC_VALIDATORS,
    useExisting: forwardRef(() => CustomAsyncValidator),
    multi: true
  }]
})
class CustomAsyncValidator implements AsyncValidator {

  valueAccessor: MyFieldComponent;

  constructor(@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {
    this.valueAccessor = valueAccessors.find(x => x.constructor === MyFieldComponent) as MyFieldComponent;
  }

  // the same as above. I would use it
  // constructor(@Self() private valueAccessor: MyFieldComponent) {}


  /**
   * presents global validation result async + sync
   */ 
  validate(control: AbstractControl): Observable<any> {
    return Observable.fromPromise(fakeAsyncValidator(1000)(control)).map(asyncResult => {
      return Object.assign({}, asyncResult, this.valueAccessor.validationResult);
    });
  }
}


function fakeAsyncValidator(timeout: number = 0) {
  return (c: AbstractControl) => {
    let resolve: (result: any) => void;
    const promise = new Promise(res => { resolve = res; });
    const res = { 'async': false };
    setTimeout(() => resolve(res), timeout);
    return promise;
  };
}

在上面的指令中,我们使用与自定义字段(my-field)相同的选择器,提供NG_ASYNC_VALIDATORS并在构造函数中注入现有组件(您可以注意到两个选项)。

最后,我们在此指令中使用validate方法尝试执行类似的操作。

<强> Plunker Example