从情侣之夜开始,我就在 augular2 中玩过表单验证。
所有基本情况都很容易实现,而且运行良好,但我坚持使用异步验证。我创建了一个非常小的例子 http://plnkr.co/edit/Xo8xwJjhlHkXrunzS8ZE它没有用。
根据来自 model_spec.ts 的测试“应该在状态更新为未决后触发事件”通过创建控制组进行注册假设以某种方式工作
builder.group({login: ["",Validators.required,validationFuctionWhichReturnsPromise]
我花了整整一个晚上才发现这段代码已经在 alfa-46 中发布(我使用的是 alfa-45)并且在更新依赖项之后异步验证开始工作。该功能很新鲜,没有完整的文档,但是
(对于那些还没有尝试过的人)基本上异步验证器是一个函数,它有一个控制参数并返回一个验证结果的 promise 。有两种方法可以注册验证器。 1) 我在示例中使用的那个和 2) 作为通过 NG_ASYNC_VALIDATORS 提供验证器的指令(请参阅 UniqLoginValidator 和 NgFormControl 以了解其工作原理)。您可以组合多个验证器(尚未测试,但执行此操作的功能在代码中,请参阅 https://github.com/angular/angular/commit/cf449dd )。
但是当我最终启动并运行验证器时,一个新问题出现了。异步验证器非常适合在服务器端验证中使用它。但是在每次 keyup 之后每次更改 model.fe 后都会调用验证。因此,如果我们将在每个键启动后向服务器发送请求,那将不是太有效的方式;)我检查了它是如何在 Angular 1 中完成的,它们有可能去抖动验证事件。
我的问题是:
- 如何使用异步验证器实现节流或去抖?我看到了一些想法,但没有一个很好(主要是因为他们需要更改 Angular 代码本身)。有没有什么有效的方法可以在不等待新的 Angular 释放的情况下做到这一点?
我正在考虑使用 debounce(来自 underscorejs)扭曲验证器函数,但它不会起作用,因为 angular 希望每次都能获得有效的 promise 。
我的第二个想法是,如果所有事件都在底层使用 RxJs,那么也许我可以在负责验证的事件流上应用去抖动。在 model.ts 中,从验证器返回的 promise 更改为可观察的,并添加了一个新的订阅者。我们无权访问 obs(Observable) 以在那里应用去抖动。
- 是否有任何方法或 id 可以更改,轻松扩展对表单验证的控制?
我在 How to trigger Form Validators in angular2 中发现了一个密切相关的问题
PS 还有其他与异步验证器相关的问题,它仍然是开放的 https://github.com/angular/angular/issues/1068
最佳答案
这是一个帮助程序类,您可以使用它来消除所有异步验证器的抖动:
import {Component} from 'angular2/core';
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import {Control} from 'angular2/common';
export class AsyncValidator {
_validate;
constructor(validator: (control: Control) => any, debounceTime = 1000) {
let source: any = new Observable((observer: Observer<Control>) => {
this._validate = (control) => observer.next(control);
});
source.debounceTime(debounceTime)
.distinctUntilChanged(null, (x) => x.control.value)
.map(x => { return { promise: validator(x.control), resolver: x.promiseResolver }; })
.subscribe(
(x) => x.promise.then(resultValue => x.resolver(resultValue),
(e) => { console.log('async validator error: %s', e); }));
}
private _getValidator() {
return (control) => {
let promiseResolver;
let p = new Promise((resolve) => {
promiseResolver = resolve;
});
this._validate({ control: control, promiseResolver: promiseResolver });
return p;
};
}
static debounce(validator: (control: Control) => any, debounceTime = 400) {
var asyncValidator = new this(validator, debounceTime);
return asyncValidator._getValidator();
}
}
然后,在使用异步验证器的地方,您所要做的就是用这个调用包装您的验证器,并像往常一样编写您的验证器:
AsyncValidator.debounce(control => this.asyncValidator(control));
这是一个用法示例:
export class AppComponent {
form: ControlGroup;
constructor(private _formBuilder: FormBuilder) {
var validator = AsyncValidator.debounce(control => this.asyncValidator(control));
this.form = _formBuilder.group({
name: ['', Validators.required, validator],
});
}
asyncValidator(control): any {
let p = new Promise(resolve => {
// get from server information need to validate control
if (control.value === 'valid value') {
resolve(null);
} else {
resolve({
asyncValidator: {
valid: false
}
});
}
});
return p;
}
}
关于validation - 一般 : asynchonious validation in angular2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33799600/