使用去抖动进行异步表单验证?

uks*_*ksz 6 angular2-forms angular

我想知道如何在异步验证器上实现去抖时间.

我有以下内容:

...
password: ['',Validators.compose([Validators.required, this.passwordValid])]
...
Run Code Online (Sandbox Code Playgroud)

哪里:

passwordValid(control:Control):{ [key: string]: any; } {
    return new Promise(resolve => {
        this._http.post('/passwordCheck', control.value)
            .subscribe(
                success=>{
                    resolve(null);
                },
                error=>{
                    resolve({passwordValid: false})
                }
            )
    })
}
Run Code Online (Sandbox Code Playgroud)

但是现在,每次击键都会触发验证.我需要添加去抖功能.我怎样才能做到这一点?

Thi*_*ier 4

这是不可能开箱即用的,因为当input使用事件触发更新时会直接触发验证器。请参阅源代码中的这一行:

如果你想在这个级别利用去抖时间,你需要获取一个与input相应 DOM 元素的事件直接链接的可观察对象。Github 中的这个问题可以为您提供上下文:

在您的情况下,解决方法是利用fromEventobservable 方法实现自定义值访问器。

这是一个示例:

const DEBOUNCE_INPUT_VALUE_ACCESSOR = new Provider(
  NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => DebounceInputControlValueAccessor), multi: true});

@Directive({
  selector: '[debounceTime]',
  //host: {'(change)': 'doOnChange($event.target)', '(blur)': 'onTouched()'},
  providers: [DEBOUNCE_INPUT_VALUE_ACCESSOR]
})
export class DebounceInputControlValueAccessor implements ControlValueAccessor {
  onChange = (_) => {};
  onTouched = () => {};
  @Input()
  debounceTime:number;

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

  }

  ngAfterViewInit() {
    Observable.fromEvent(this._elementRef.nativeElement, 'keyup')
      .debounceTime(this.debounceTime)
      .subscribe((event) => {
        this.onChange(event.target.value);
      });
  }

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

  registerOnChange(fn: () => any): void { this.onChange = fn; }
  registerOnTouched(fn: () => any): void { this.onTouched = fn; }
}
Run Code Online (Sandbox Code Playgroud)

并以这种方式使用它:

function validator(ctrl) {
  console.log('validator called');
  console.log(ctrl);
}

@Component({
  selector: 'app'
  template: `
    <form>
      <div>
        <input [debounceTime]="2000" [ngFormControl]="ctrl"/>
      </div>
      value : {{ctrl.value}}
    </form>
  `,
  directives: [ DebounceInputControlValueAccessor ]
})
export class App {
  constructor(private fb:FormBuilder) {
    this.ctrl = new Control('', validator);
  }
}
Run Code Online (Sandbox Code Playgroud)

请参阅此plunkr:https://plnkr.co/edit/u23ZgaXjAvzFpeScZbpJ ?p=preview 。