2016-08-06 18 views
2

ngModelのカスタムバリデータロジックを実装する最も簡単な方法を理解しようとします。私は現在のデータを保存する事前定義されたモデル(インターフェイス)を持っているので、新しいFormGroup/FormControl(モデル駆動型)アプローチに対処したくありません。コンポーネント内のAngular2 ngModelバリデータ

必要なすべてのデータが既にある場合、FormControlsとまったく同じスキーマを構築するのはなぜですか?

は、ここに私のコード(https://plnkr.co/edit/fPEdbMihRSVqQ5LZYBHO)です:

import { Component, Input } from '@angular/core'; 


export interface MyWidgetModel { 
    title:string; 
    description:string; 
} 


@Component({ 
    selector: 'my-widget', 
    template: ` 
    <h4 *ngIf="!editing">{{data.title}}</h4> 
    <input *ngIf="editing" type="text" name="title" [(ngModel)]="data.title"> 

    <p *ngIf="!editing">{{data.description}}</p> 
    <textarea *ngIf="editing" name="description" [(ngModel)]="data.description" (ngModelChange)="customValidator($event)"></textarea> 

    <button (click)="clickEditing()">{{editing ? 'save' : 'edit'}}</button> 

    ` 
    styles: [ 
    ':host, :host > * { display: block; margin: 5px; }', 
    ':host { margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #eee; }', 
    '.ng-invalid { background-color: #FEE; }' 
    ] 

}) 
export class MyWidgetComponent { 
    @Input() data:MyWidgetModel; 

    constructor() { 
    this.editing = false; 
    } 

    clickEditing() { 
    this.editing = !this.editing; 
    } 

    customValidator(value:string) { 
    console.log(this, value); //should be: MyWidgetComponent 
    //How to set 'invalid' state here? 
    } 

} 

あなたは、私はすぐにオン/オフ編集モードをオンにすることができます見ることができると私は直接その場で自分のデータを編集することができたよう。

私の質問は、ngModelのng-valid/ng-invalid状態を自分のコンポーネントから直接管理する方法ですか?

  • データモデルが既に存在する場合、FormGroups、FormControlsに同じ構造を持つ新しいローカル変数を作成するのはなぜですか?
  • コンポーネント自体に必要なビジネスロジックが実装されているため、すべてのビジネスルールバリデータもここで実装する必要があります。
  • 複雑な検証ロジックが多数あります。これらは、入力の純粋なテキスト値と、必須、長さ、パターンなどの簡単なチェックを使用して実装することはできません。
  • 上記のことから、すべての実際のビジネスルール検証を解決するには、

答えて

5

最後に、私はやり方を考え出しました。私はこれが最も簡単だと思います。 私はまた、プランナーを更新しました:https://plnkr.co/edit/fPEdbMihRSVqQ5LZYBHO

ステップバイステップで見てみましょう。

1 - 通常と同じようにValidatorインターフェイスを実装する単純で最小限のディレクティブを作成しますが、検証ロジックは記述しません。その代わりに、セレクタと同じ名前の関数型のInput()フィールドを指定します。これにより、このバリデータの外で実際のロジックを実装することができます。 validate(...)関数の内部では、その外部Input()関数を呼び出すだけです。

import { Directive, forwardRef, Input } from '@angular/core'; 
import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn } from '@angular/forms'; 

@Directive({ 
    selector: '[myvalidator][ngModel],[myvalidator][ngFormControl]', 
    providers: [{ 
    multi: true, 
    provide: NG_VALIDATORS, 
    useExisting: forwardRef(() => MyValidator)  
    }] 
}) 
export class MyValidator implements Validator { 
    @Input() myvalidator:ValidatorFn; //same name as the selector 

    validate(control: AbstractControl):{ [key: string]: any; } { 
    return this.myvalidator(control); 
    } 

} 

2 - カスタムバリデータを使用するには、コンポーネントをインポートしてコンポーネントのディレクティブ配列に追加するだけです。テンプレートマークアップでは、他の指示と同様に使用します。

<input type="text" name="title" [(ngModel)]="data.title" [myvalidator]="validateTitle()"> 

ここでのトリックは正しいです。バリデータのInput()関数に渡される値は、関数呼び出しです。バリデータ関数を返します。ここでは、次のとおりです。

validateTitle() { 
    return <ValidatorFn>((control:FormControl) => { 

     //implement a custom validation logic here. 
     //the 'this' points the component instance here thanks to the arrow syntax. 

     return null; //null means: no error. 
    }); 

公式Angular2と完全に互換性上記のすべては、バリデータ - 必要な、パターンなどを - ので、私たちのカスタムバリデータはそれ以上のトリックなしに組み合わせることができます。

編集: 各検証のためのコンポーネントのコンストラクタで作成されたローカル変数場合には、より簡単で効果的な方法を実装できます。

このアプローチを用いて、我々は一度だけValidatorFn関数を作成すべての検証要求ではなく、 1関数呼び出しeleminated:validateTitle()。したがって、テンプレートでは変数をバインドできます:

<input type="text" name="title" [(ngModel)]="data.title" [myvalidator]="validateTitle"> 
関連する問題