Вложенные массивы в Angular 2 реактивные формы?

Я использовал следующий учебник для создания реактивных форм в Angular 2, и он работает хорошо.

https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2

Тем не менее, я сейчас пытаюсь добавить массив в массиве. Используя описанное выше руководство, я создал форму "Организация", которая может содержать массив групп "Контакты". Но я не могу успешно адаптировать настройки, чтобы каждая группа "Контакты" содержала массив групп "Электронная почта".

Я не смог найти учебник или пример, который охватывает это и был бы благодарен за любые указатели.

1 ответ

Решение

Используя описанное выше руководство, я создал форму "Организация", которая может содержать массив групп "Контакты". Но я не могу успешно адаптировать настройки, чтобы каждая группа "Контакты" содержала массив групп "Электронная почта".

Учебник выше дает вам все, что вам нужно.

Я полагаю, вы хотите структуру, как это.

Для начала нужен какой-то компонент (AppComponent в моем случае) где вы объявляете root FormGroup, Я назвал это trustForm ниже.

app.component.ts

export class AppComponent {
  trustForm: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.trustForm = this.fb.group({
      name: '',
      contracts: this.fb.array([])
    });

    this.addContract();
  }

  initContract() {
    return this.fb.group({
      name: '',
      emails: this.fb.array([])
    });
  }

  addContract() {
    const contractArray = <FormArray>this.trustForm.controls['contracts'];
    const newContract = this.initContract();

    contractArray.push(newContract);
  }

  removeContract(idx: number) {
    const contractsArray = <FormArray>this.trustForm.controls['contracts'];
    contractsArray.removeAt(idx);
  }
}

В этом компоненте у вас также есть несколько методов, которые помогут вам манипулировать первым уровнем FormArray - contracts

app.component.html

<div class="container">
    <form [formGroup]="trustForm">
        <h3>Add trust</h3>

        <div class="form-group">
            <label>Name</label>
            <input type="text" class="form-control" formControlName="name">
        </div>

        <!--contracts-->
        <div formArrayName="contracts">
            <div *ngFor="let contract of trustForm.controls.contracts.controls; let i=index" class="panel panel-default">
                <div class="panel-heading">
                    <span>Contract {{i + 1}}</span>
                    <span class="glyphicon glyphicon-remove pull-right" *ngIf="trustForm.controls.contracts.controls.length > 1" (click)="removeContract(i)"></span>
                </div>
                <div class="panel-body" [formGroupName]="i">
                    <contract [group]="trustForm.controls.contracts.controls[i]"></contract>
                </div>
            </div>
        </div>
        <div class="margin-20">
            <button (click)="addContract()" class="btn btn-primary">
                Add another contract +
            </button>
        </div>

    </form>

    <h5>Details</h5>
    <pre>{{ trustForm.value | json }}</pre>
</div>

Существует не отличается от корневого HTML из учебника, кроме разных FormArray название.

Затем вам нужно построить компонент контракта, который будет похож на AppComponent

contract.component.ts

export class ContractComponent {
    @Input('group') contractGroup: FormGroup;

    constructor(private fb: FormBuilder) { }

    addEmail() {
        const emailArray = <FormArray>this.contractGroup.controls['emails'];
        const newEmail = this.initEmail();

        emailArray.push(newEmail);
    }

    removeEmail(idx: number) {
        const emailArray = <FormArray>this.contractGroup.controls['emails'];
        emailArray.removeAt(idx);
    }

    initEmail() {
        return this.fb.group({
            text: ''
        });
    }
}

contract.component.html

<div [formGroup]="contractGroup">
    <div class="form-group">
        <label>Name</label>
        <input type="text" class="form-control" formControlName="name">
    </div>

    <!--emails-->
    <div formArrayName="emails">
        <div *ngFor="let email of contractGroup.controls.emails.controls; let i=index" class="panel panel-default">
            <div class="panel-heading">
                <span>Email {{i + 1}}</span>
                <span class="glyphicon glyphicon-remove pull-right" *ngIf="contractGroup.controls.emails.controls.length > 1" (click)="removeEmail(i)"></span>
            </div>
            <div class="panel-body" [formGroupName]="i">
                <email [group]="contractGroup.controls.emails.controls[i]"></email>
            </div>
        </div>
    </div>
    <div class="margin-20">
        <button (click)="addEmail()" class="btn btn-primary">
            Add another email +
        </button>
    </div>

</div>

Как видите, мы просто заменим contracts в emailsFormArray и мы также проходим FormGroup отправить компонент по электронной почте

И, наконец, вам нужно будет только заполнить EmailComponent с желаемыми полями.

email.component.ts

export class EmailComponent {
    @Input('group') emailGroup: FormGroup;
}

email.component.html

<div [formGroup]="emailGroup">
    <div class="form-group">
        <label>Text</label>
        <input type="text" class="form-control" formControlName="text">
    </div>
</div>

Завершенную версию вы можете найти на Plunker.

Если вы думаете, что это решение не кажется правильным, потому что родительский компонент содержит описание дочернего компонента, например initContract а также initEmails Вы можете взглянуть на более сложный

Пример плунжера

где каждый компонент отвечает за свою функциональность.

Если вы ищете решение для шаблонно-управляемых форм, прочитайте эту статью:

Другие вопросы по тегам