将组件动态添加到Form中的FormArray(Angular 2/4)

时间:2017-06-10 09:04:40

标签: angular

我有一个注册表单,用户可以在其中添加一个或多个地址,一个或多个电话添加到新的或现有的组织,地址和电话实际上是(可重复使用的)组件。

例如,Phone组件与Android联系人详细信息中的组件类似,它有3个FormControls:一个Type(下拉列表),number(输入)和一个删除按钮。

最后,必须提交整个表格以保存信息。

问题:如何动态地将电话添加到表单并显示已存在的电话? (下面的代码和标记)。我很感激你的时间和精力来回答我!

组织detail.component.ts

import { Component, Input } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, FormControl, Validators } from '@angular/forms';

import { Organization } from './organization';
import { PhoneDetailComponent } from "../phone-detail/phone-detail.component";

@Component({
    selector: 'organization-detail',
    templateUrl: './organization-detail.component.html',
    styleUrls: ['./organization-detail.component.css']
})

export class OrganizationDetailComponent {
    organizationForm: FormGroup;

    constructor (private fb: FormBuilder){
      this.createForm();
    }

    createForm() {
        this.organizationForm = this.fb.group({
        accountingId: [''],
        externalId: '',
        isHost: false,
        logoPath: '',
        name: ['', 
            [Validators.required,
            Validators.minLength(4),
            Validators.maxLength(24)]
            ], // <--- the FormControl called "name"
        notes: '',
        registrationNo: '',
        vATId: '',
        webSite: '',
        phones: new FormArray([])
        //phones: new Array<PhoneDetailComponent>
        });
    }

    onSubmit() {
      console.log(this.organizationForm);  
    }

    onAddPhone() {
      const control = new PhoneDetailComponent();
      (<FormArray>this.organizationForm.get('phones')).push(control);
    }

}

组织detail.component.html

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
      <h2>Organization Detail</h2>
      <form [formGroup]="organizationForm" (ngSubmit)="onSubmit()" class="form-horizontal">
        <div class="form-group">
          <label for="isHost"> Is host:</label>
          <input type="checkbox" id="isHost" formControlName="isHost" class="check" />
        </div>
        <div class="form-group">
          <label for="name">Name:</label>
          <input type="text" id="name" class="form-control" formControlName="name" placeholder="Organization name" />
          <span 
            *ngIf="!organizationForm.get('name').valid && organizationForm.get('name').touched" 
            class="help-block">Please enter a valid name!</span>
        </div>
        <div class="form-group">
          <label for="accountingId">Accounting Id:</label>
          <input type="text" id="accountingId" class="form-control" formControlName="accountingId" />
        </div>
        <div class="form-group">
          <label for="externalId">External Id:</label>
          <input type="text" id="externalId" class="form-control" formControlName="externalId" />
        </div>
        <div class="form-group">
          <label for="registrationNo">Registration No:</label>
          <input type="text" id="registrationNo" class="form-control" formControlName="registrationNo" />
        </div>
        <div class="form-group">
          <label for="vATId">VAT Id:</label>
          <input type="text" id="vATId" class="form-control" formControlName="vATId" />
        </div>
        <div class="form-group">
          <label for="webSite">Web site:</label>
          <input type="text" id="webSite" class="form-control" formControlName="webSite" />
        </div>
        <div class="form-group">
          <label for="logoPath">Logo path:</label>
          <input type="text" id="logoPath" class="form-control" formControlName="logoPath" />
        </div>
        <div class="form-group">
          <label for="notes">Notes:</label>
          <textarea id="notes" class="form-control" formControlName="notes" rows="3"></textarea>
        </div>
        <div formArrayName="phones">
          <h4>Phones:</h4>
          <button class="btn btn-default" type="button"
            (click)="onAddPhone()">
            Add phone
          </button>
          <div class="form-group"
            *ngFor="let phoneControl of organizationForm.get('phones').controls; let i = index">
            <!--<input type="text" class="form-control" [formControlName]="i">-->
            <phone-detail></phone-detail>
          </div>
        </div>
        <div class="form-group">
          <div class="input-group">
            <input type="text" class="form-control">
            <span class="input-group-btn">
                  <button class="btn btn-default" type="button">Go!</button>
            </span>
          </div>
        </div>
        <button class="btn btn-primary" type="submit">Submit</button>
      </form>
    </div>
  </div>
</div>
<p>Form value: {{ organizationForm.value | json }}</p>
<p>Form status: {{ organizationForm.status | json }}</p>

电话detail.component.ts

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

import { Phone } from "./phone";

@Component({
  selector: 'phone-detail',
  templateUrl: './phone-detail.component.html',
  styleUrls: ['./phone-detail.component.css']
})
export class PhoneDetailComponent implements OnInit {
  @Input('phoneItem') item: Phone;

  constructor() { }

  ngOnInit() {
  }
}

电话detail.component.html

<div class="container">
  <div class="row">
    <div class="col-xs-3">
      <select class="form-control">
        <option>1</option>
        <option>2</option>
        <option>3</option>
        <option>4</option>
        <option>5</option>
      </select> 
    </div>
    <div class="col-xs-7">
      <input type="text" class="form-control">
    </div>
    <div class="col-xs-2">
      <button class="btn">X</button>
    </div>
  </div>
</div>

2 个答案:

答案 0 :(得分:7)

在您的父母中,请使用formarray:

phones: this.fb.array([])

然后在父模板中将此formarray中的每个表单组传递给子项:

<button (click)="addPhone()">Add phone</button>
<div formArrayName="phones">
  <div *ngFor="let ctrl of organizationForm.controls.phones.controls; let i=index">
    <button (click)="removePhone(i)">X</button>
    <phone-detail [group]="ctrl"></phone-detail>
  </div>
</div>

在儿童使用中@Input

@Input() group: FormGroup;

并在模板中添加表单控件和formgroup:

<div [formGroup]="group">
  <select formControlName="type">
    <option>1</option>
    <option>2</option>
    <option>3</option>
    <option>4</option>
    <option>5</option>
  </select> 
  <input type="text" formControlName="num">
</div>

最后删除并添加放置在父级中的表单组:

initPhone() {
  return this.fb.group({
    type: [''],
    num: ['']
  });
}

addPhone() {
    const control = this.organizationForm.controls.phones;
    control.push(this.initPhone());
}

removePhone(i: number) {
    const control = this.organizationForm.controls.phones;
    control.removeAt(i);
}
关于这个问题,

This article 值得一读!

答案 1 :(得分:0)

非常感谢您的回复,帮了很多忙! 我用一个事件来触发删除手机注册。 适合我情况的解决方案是:

在parent organization-edit.component.html中:

<div formArrayName="phones">
  <h4>Phones:</h4>
  <button class="btn btn-default" type="button"
    (click)="onAddPhone()">
    Add phone
  </button>
  <div class="form-group"
     *ngFor="let phoneControl of organizationForm.get('phones').controls; let i = index">
      <phone-detail [formGroupName]="i" (phoneDeleted)="onDeletePhone(i)"></phone-detail>
  </div>
</div>

organization-edit.component.ts(以前的细节!):

createForm() {
  this.organizationForm = this.fb.group({
    accountingId: [''],
  ......
  phones: new FormArray([]) 
});

onAddPhone() {
  const control = new FormControl(null, Validators.required);
  (<FormArray>this.organizationForm.get('phones')).push(control);
}

onDeletePhone(index: any){
    (<FormArray>this.organizationForm.get('phones')).removeAt(index);
}

电话detail.component.html

<div class="row">
<div class="col-xs-3">
  <select class="form-control">
    <option>1</option>
    <option>2</option>
    <option>3</option>
    <option>4</option>
    <option>5</option>
  </select> 
</div>
<div class="col-xs-7">
  <input type="number" class="form-control">
</div>
<div class="col-xs-2">
  <button 
    type="button"
    class="btn btn-danger"
    (click)="onDeletePhone()">X</button>
</div>

电话detail.component.ts:

export class PhoneDetailComponent implements OnInit {
  phoneForm: FormGroup;
  @Input('phoneItem') item: Phone;
  @Output() phoneDeleted = new EventEmitter<void>();
  @Output() phone: Phone;

  constructor(private fb: FormBuilder) {
    this.phoneForm = this.fb.group({
       type: [''],
       number: ['']
    });
  }

  onDeletePhone(){
    this.phoneDeleted.emit();
  }

}