我想知道如何在异步验证器上实现去抖时间。
我有以下内容:
...
password: ['',Validators.compose([Validators.required, this.passwordValid])]
...
其中:
passwordValid(control:Control):{ [key: string]: any; } {
return new Promise(resolve => {
this._http.post('/passwordCheck', control.value)
.subscribe(
success=>{
resolve(null);
},
error=>{
resolve({passwordValid: false})
}
)
})
}
但是现在,每次击键都会触发验证。我需要添加去抖功能。我怎么能这样做?
答案 0 :(得分:4)
由于在input
事件用于触发更新时直接触发验证器,因此无法开箱即用。请参阅源代码中的这一行:
如果您想在此级别利用去抖时间,则需要获得与相应DOM元素的input
事件直接链接的observable。 Github中的这个问题可以为您提供上下文:
在您的情况下,解决方法是使用fromEvent
可观察方法实现自定义值访问器。
以下是一个示例:
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; }
}
并以这种方式使用它:
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);
}
}
请参阅此plunkr:https://plnkr.co/edit/u23ZgaXjAvzFpeScZbpJ?p=preview。
答案 1 :(得分:1)
另一个更简单的实现可以如下面的答案所述:
https://stackoverflow.com/a/38022310/4655056
您还可以在创建新订阅/请求之前更新该实现以取消订阅活动订阅。
这是我的异步验证器示例:
private _uniqueUsernameValidator(control: FormControl): Promise<any> {
if (this._uniqueUsernameSubscription) {
this._uniqueUsernameSubscription.unsubscribe();
}
if (this._uniqueUsernameTimeout) {
clearTimeout(this._uniqueUsernameTimeout);
}
return new Promise((resolve, reject) => {
this._uniqueUsernameTimeout = setTimeout(() => {
this._uniqueUsernameSubscription = this._SecurityResource.getUsernameExists(control.value).subscribe(resp => {
if (resp === false) {
resolve(null);
} else {
resolve({customMessage: {message: 'This username is already taken'}});
}
});
}, 1000);
});
}