web-dev-qa-db-ja.com

Angular2のフォームに配列を割り当てて検証する方法

Javascriptの私のモデル(this.profile)には、{email, isDefault, status}の配列であるemailsというプロパティがあります。

それから私はそれを以下のように定義しました

  this.profileForm = this.formBuilder.group({
    .... other properties here
    emails: [this.profile.emails]
  });

  console.log(this.profile.emails); //is an array
  console.log(this.profileForm.emails); // undefined

htmlファイルで私はそれを使用しました

    <div *ngFor="let emailInfo of profileForm.emails">
        {{emailInfo.email}}
        <button (click)="removeEmail(emailInfo)">
           Remove 
        </button>
    </div>

formGroupに追加せず、配列として使用する場合(以下のように)、正常に機能しますが、この配列を空にしないというビジネスルールがあり、フォームを設定できません。この長さに基づく検証

  emails : [];
  this.profileForm = this.formBuilder.group({
    .... other properties here
  });

  this.emails = this.profile.emails;
  console.log(this.profile.emails); //is an array
  console.log(this.emails); // is an array

また、formBuilder.arrayを使用してみましたが、これはデータの配列ではなく、コントロールの配列を使用するためのものです。

   emails: this.formBuilder.array([this.profile.emails])

次に、私の質問は、配列をモデルからUIにバインドする方法と、配列の長さを検証する方法です。

6
Reza

モデルからUIに配列をバインドするにはどうすればよいですか?

さて、私はすべてのメールを_profile.emails_からformArrayにプッシュしたいと思います。そうしないと、値はありますが、検証はありません。

配列の長さをどのように検証する必要がありますか?

Validators.minLength(Number)は、他のcontrolと同じように使用できます。

デモコード:

コンポーネント:

_export class AnyComponent implements OnInit {

  profileForm: FormGroup;
  emailsCtrl: FormArray;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit(): void {

    this.emailsCtrl = this.formBuilder.array([], Validators.minLength(ANY_NUMBER));
    this.profile.emails.forEach((email: any) => this.emailsCtrl.Push(this.initEmail(email)));

    this.profileForm = this.formBuilder.group({
      // ... other controls
      emails: this.emailsCtrl
    });
  }

  private initEmail = (obj: any): FormGroup => {
    return this.formBuilder.group({
      'email': [obj.email], //, any validation],
      'isDefault': [obj.isDefault] //, any validation]
    });
  }
}
_

テンプレート:

_<div *ngFor="let emailInfo of emailsCtrl.value">
  {{emailInfo.email}}
  <button (click)="removeEmail(emailInfo)">
    Remove
  </button>
</div>
<div *ngIf="emailsCtrl.hasError('minlength')">
  It should have at least {{emailsCtrl.getError('minlength').requiredLength}} emails
</div>
_

PS1:Validators.minLength(param)methodのパラメータは1より大きくなければならないことに注意してください、それ以外の場合は検証されません。

ご覧のとおり、 source whencontrolが空の場合、自動的にnullを返します。

次に、期待どおりに機能させるために、requiredValidatorを追加できます。

_this.emailsCtrl = this.formBuilder.array([], Validators.compose([Validators.required, Validators.minLength(ANY_NUMBER > 1)]);
_

そしてテンプレートで:

_<div *ngIf="emailsCtrl.invalid">
  <span *ngIf="emailsCtrl.hasError('required')">
    It's required
  </span>
  <span *ngIf="emailsCtrl.hasError('minlength')">
    It should have at least {{emailsCtrl.getError('minlength').requiredLength}} emails
  </span>
</div>
_

PS2:

削除したいメールのインデックスをremoveEmail関数に渡す方が理にかなっていると思うので、indexOfspecificemailのインデックスを取得します。あなたはこのようなことをすることができます:

_<div *ngFor="let emailInfo of emailsCtrl.value; let i = index">
  {{emailInfo.email}}
  <button (click)="removeEmail(i)">
    Remove
  </button>
</div>
_

コンポーネント:

_removeEmail(i: number): void {
  this.emailsCtrl.removeAt(i);
}
_

このシンプルなものを見てください DEMO

6
developer033

これは私にとってはうまくいきます(角度2.1.2)。このアプローチにより、電子メールのカスタム検証を柔軟に定義できます。

 this.profileForm = this.formBuilder.group({
    emails: [this.profile.emails, FormValidatorUtils.nonEmpty]
    // ......
  });

export class FormValidatorUtils {

  static nonEmpty(control: any) {
    if (!control.value || control.value.length === 0) {
      return { 'noElements': true };
    }
    return null;
  }
}
4
artemisian