web-dev-qa-db-ja.com

コンポーネント内で双方向のバインディングと検証を行うカスタムangular2フォーム入力コンポーネント

コンポーネント内で検証を行うこともできる、双方向バインディング入力コンポーネントを作成する方法はありますか?

私が達成しようとしているのは、次のようにフォームに並べることができるコンポーネントを用意することです。

<form #f="ngForm">
            <my-form-input [(inputModel)]="name" [inputField]="myFormInputName"></my-form-input>
            <my-form-input [(inputModel)]="name2" [inputField]="myFormInputName2"></my-form-input>
...
            <my-form-input [(inputModel)]="lastItem" [inputField]="lastItemName"></my-form-input>

</form>

私は次の設定をしていて、それを正しくする方法を理解できません:

コンポーネント:

import {Component,Input, Output,EventEmitter} from 'angular2/core'
import {FORM_DIRECTIVES}    from 'angular2/common';

@Component({
  selector: 'my-form-input',
  directives: [FORM_DIRECTIVES],
  template:
    `
    <input type="text" class="form-control"  id="i1" required [ngModel]="inputModel" (ngModelChange)="onChangeInput($event)" ngControl="ctrl" #ctrl="ngForm"/>
    <p>{{"Is field valid? I would like to make some decisions here depending on that: "+ctrl.valid}}</p>

  `
})
export class InputComponent {

  constructor(){};

  @Input()  inputField:string;
  @Input()  inputModel: Object;
  @Output() inputModelChange = new EventEmitter();

  onChangeInput(event){
    this.inputModel=event;
    this.inputModelChange.emit(event);
  }
}

アプリ:

//our root app component
import {Component} from 'angular2/core'
import {FORM_DIRECTIVES}    from 'angular2/common';
import {InputComponent} from './my.input'


@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
      <p>Is there a way to make a custom 2 way binding form input component having also validation?</p>
      <form #f="ngForm">

        <my-form-input [(inputModel)]="name" [inputField]="myFormInputName"></my-form-input>

        <p>{{name}}</p>
      </form>
    </div>
  `,
  directives: [InputComponent,FORM_DIRECTIVES]
})
export class App {
  constructor() {
    this.name = 'Angular2'
  }
}

私はまた私の問題を説明するためにプランカーを作りました: http://plnkr.co/edit/0vXjHbQmv7v7EKQcLWaa?p=preview

14
Andris Krauze

フォームコントロールをコンポーネントに渡して、入力専用のコントロールを作成できます。この新しいコントロールに基づいて、valid属性がfalseの場合にエラーを表示します。

@Component({
  selector: 'my-form-input',
  directives: [FORM_DIRECTIVES],
  template: `
    <input type="text" class="form-control"  id="i1"   
       [ngModel]="inputModel"
       (ngModelChange)="onChangeInput($event)"
       [ngFormControl]="formCtrl.controls[inputField]"/>
    <p>Is field valid? I would like to make some decisions
       here depending on that: {{formCtrl.controls[inputField].valid}}
    </p>
  `
})
export class InputComponent implements OnInit {
  @Input()  inputField:string;
  @Input()  formCtrl;
  @Input()  inputModel: Object;
  @Output() inputModelChange = new EventEmitter(); 

  ngOnInit() {
    this.formCtrl.control.addControl(
        this.inputField, new Control('', Validators.required));
  }

  onChangeInput(event){
    this.inputModel=event;
    this.inputModelChange.emit(event);
  }
}

フォーム全体の状態を入力コンポーネント内で作成したコントロールと一致させるには、addControlメソッドを使用する必要があります。

あなたの場合、ngControlディレクティブを使用してコントロールをインラインで定義します。私はいくつかのテストを行いましたが、このように機能させることはできません...

親コンポーネントからこのコンポーネントを使用する方法は次のとおりです。

@Component({
  selector: 'my-app', 
  template: `
    <form #f="ngForm">
      <my-form-input [(inputModel)]="name" [inputField]="myFormInputName" [formCtrl]="f"></my-form-input>
    </form>
  `,
  directives: [ FORM_DIRECTIVES, InputComponent ]
})
export class AppComponent {
}

起動直後はチェックの問題が残っていました。フォームのグローバル状態が更新されず、次のエラーが発生しました。

Expression '
    Valid : {{f.valid}} in AppComponent@1:24' has changed after it was checked. Previous value: '
    Valid : true'. Current value: '
    Valid : false'

この側面を修正するには、ChangeDetectorRefクラスとそのdetectChangesメソッドに基づくJulienの回答を見てください...

Plunkrのサンプルは次のとおりです: https://plnkr.co/edit/Z4uOUq2q4iXdpo0J6R1o?p=preview

5

ティエリーの答えは部分的に良いです。enableProdModeの場合、問題を隠しているだけです。コンポーネントを更新していません。

フォームコンポーネントの初期化後に「detectChange」を呼び出す必要があります。

export class AppComponent {
    constructor(private cdr: ChangeDetectorRef) {}
    ngOnInit() {
        this.cdr.detectChanges();
    }
}
4
Julien Alary