2017-03-06 15 views
3

誰もがカスタムフィールドのクラスに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()方法と、私はこの方法で両方の私の同期および非同期検証を行う必要があるとリターン一つの大きな観測可能(潜在的に包む複数のエラーキー)?私はこれについてあまりよく分かりません。

サイドノート:私は仕事に得ることができる何をインラインuseValueまたはuseClassと別のクラスのいずれかとして、プロバイダに直接非同期バリを宣言しています。しかし、コンポーネントクラスのメソッドとしてuseExistingとしたいと思います。

+0

'FieldEntityReferenceComponent'は何ですか? – yurzui

+0

申し訳ありませんが、コピー貼り付けが間違っていた...それは 'MyFieldComponent'と言うべきです – AngularChef

答えて

3

私は完全にあなたの要件が何であるかを理解していないが、私はあなたに多分あなたを助けるいくつかのアイデアを与えることができます。

のでControlValueAccessorValidatorを実装して、当社のカスタムフィールド(同期)から始めましょう:私たちが使用上のディレクティブで

@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; 
    }; 
} 

AsyncValidatorを実装することを宣言ディレクティブの後

@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; 
    } 
} 

私たちのカスタムフィールド(my-field)と同じセレクターは、NG_ASYNC_VALIDATORSを提供し、既存のコンポーネントをコンストラクターに注入します(2つのオプションがあります)。

そして最後に、我々はあなたが望むものと同様のものをやろうとしているこのディレクティブでvalidate方法があります。

Plunker Example

+0

あなたの答えとあなたの時間、yurzuiに感謝します。その理由は、バリデーターが1つのフィールドと1つのフィールドだけで使用されるようになると、フィールド・コードの一部にすることがより密接に感じられるということです。また、 'Http'を使う必要のある非同期バリデータについて話しているので、依存性注入(ディレクティブまたはコンポーネントのいずれか)をサポートする何らかの種類のAngularコンストラクタに属していなければなりません。単なる機能や階級ではありませんでした。今、あなたはあなたの答えをいくつか洞察し、私はいくつかの質問があります...(次のコメントに続きます) – AngularChef

+0

ディレクティブをフィールドのセレクタと一致させることをお勧めします。このようにして、ディレクティブはカスタムフィールドに自動的に適用されます。 'CustomAsyncValidator'のコンストラクタでオプションのインジェクションについて説明できますか?私はそれが非同期バリデータを同期バリデータからの結果にアクセスさせることができますが、それは本当に必要ですか?両方の 'validate()'メソッド(sync + async)がそれらの値を別々に返す場合**自動的にマージされませんか? – AngularChef

+0

はい。私は同期バリデータにアクセスしています。定義されていない場合、エラーを防ぐために '@ Options'が使用されています。そして、私はちょうどangular2がそれをしていることに気づいた。https://github.com/angular/angular/blob/4.0.0-rc.2/modules/%40angular/forms/src/directives/reactive_directives/form_control_name.ts#L102私は午前それを自動的にマージすることについてはわかりません。 Angularは、同じ技術(「ディレクティブをフィールドのセレクタと一致させることをお勧めします)を使用して、指示間の通信を行います。https://github.com/angular/angular/blob/4.0.0-rc.2/modules/% 40angular/forms/src/directives/ng_control_status.ts#L45-L48 – yurzui

関連する問題