web-dev-qa-db-fra.com

Comment itérer un groupe de formulaires avec un tableau dans Angular2

Je travaille sur un formulaire piloté par modèle et je n'arrive pas à le faire ajouter des éléments à une liste affichée avec ngFor. Je reçois actuellement une erreur lorsque j'essaie d'itérer ma liste.

Erreur:

Error: Cannot find control with path: 'locations -> i'
    at new BaseException (exceptions.ts:21)
    at _throwError (shared.ts:80)
    at Object.setUpFormContainer (shared.ts:66)
    at FormGroupDirective.addFormGroup (form_group_directive.ts:74)
    at FormGroupName.AbstractFormGroupDirective.ngOnInit (abstract_form_group_directive.ts:37)
    at DebugAppView._View_PersonFormComponent4.detectChangesInternal (PersonFormComponent.ngfactory.js:3197)
    at DebugAppView.AppView.detectChanges (view.ts:260)
    at DebugAppView.detectChanges (view.ts:378)
    at DebugAppView.AppView.detectContentChildrenChanges (view.ts:279)
    at DebugAppView._View_PersonFormComponent2.detectChangesInternal (PersonFormComponent.ngfactory.js:1995)
Raw  person-form-builder.service.ts

formBuilderService:

import {Injectable} from "@angular/core";
import {Validators, FormBuilder} from '@angular/forms';

import {Person} from './../components/person/person';

@Injectable()

export class PersonFormBuilderService {

    constructor(private fb: FormBuilder) {
    }

    getForm(person: Person) {
        return this.fb.group({
            _id: [person._id],
            name: this.fb.group({
                first: [person.name.first],
                middle: [person.name.middle],
                last: [person.name.last],
                full: [person.name.full],
            }),
            locations: this.fb.array([
                this.initLocation(),
            ]),
            files: this.fb.array([
                this.initFiles(),
            ]),
            skills: this.fb.array([
                this.initSkills(),
            ]),
        });
    }

    initLocation() {
        return this.fb.group({
            isDefault: [false, Validators.required],
            location: ['', Validators.required],
            roles: ['', Validators.required],
            isContact: [false, Validators.required],
            contactPhone: ['', Validators.required],
            contactPhoneExt: ['', Validators.required],
        });
    }

    initFiles() {
        return this.fb.group({
            originalName: ['', Validators.required],
        });
    }

    initSkills() {
        return this.fb.group({
            name: ['', Validators.required],
            isrequired: [false, Validators.required],
            expireDate: ['', Validators.required],
            canOverride: [false, Validators.required],
        });
    }

    addLocation(control) {
        control.Push(this.initLocation());
    }

    removeLocation(i: number, control) {
        control.removeAt(i);
    }
}

forme:

<div formGroup="form">
  <div formArrayName="locations">
      <div *ngFor="let location of form.controls.locations.controls; let i=index">
          <span>Location {{i + 1}}</span>
          <div formGroupName="i">
              <label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect">
                  <input type="checkbox" class="mdl-checkbox__input"
                         formControlName="isDefault" [checked]="">
              </label>
          </div>
      </div>
  </div>
</div>

form-component.ts:

import {Component} from '@angular/core';
import {FormGroup, FormArray} from '@angular/forms';

@Component({
    moduleId: module.id,
    selector: 'person-form-component',
    templateUrl: 'person-form.component.html',
    providers: [PersonService, PersonFormBuilderService]
})

export class PersonFormComponent {
  getPerson(personId) {
      this.personService.getPerson(this.personId).subscribe(res => {
          this.person = res.data;
          this.form = this.personFormBuilderService.getForm(this.person);
      });
  }

  addLocation() {
      let control = <FormArray> this.form.controls['locations'];
      this.personFormBuilderService.addLocation(control);
  }
}

https://Gist.github.com/jpstokes/11551ff5d8c76514005c6c9fd8a554dd

11
Jason Stokes

Fixé !!!

Donc, apparemment, j'ai besoin de lire les principes fondamentaux d'Angular2 parce que je pensais que mon erreur était légale. Fondamentalement, j'ai ignoré les crochets autour de formGroupName dans le tutoriel parce que je l'ai fait plusieurs fois sans problème, mais pas cette fois. Donc, pour corriger, j'ai simplement ajouté les supports:

<div formGroupName="i"> => <div [formGroupName]="i">
11
Jason Stokes

Voici la solution qui a fonctionné pour moi. https://plnkr.co/edit/cs244r

Modèle HTML:

<div>
      <h2>RegionId: {{regionId}}</h2>
      <h2>Region:  {{region.name}}</h2>
    </div>
    <form [formGroup]="regionFormGroup">
      Region Name: <input type="text" formControlName="regionName" [(ngModel)]="region.name" />
      <div formArrayName="customersArray">
      <table class="simple-table">
        <tr>
          <th>Customer</th>
          <th>Current Period</th>
          <th>Previous Period</th>
        </tr>
        <tbody>
          <tr [formGroupName]="i" *ngFor="let customerGroup of regionFormGroup.controls.customersArray.controls; let i = index">
            <td>{{region.customers[i].name}} - index {{i}}</td>
            <td><input type="text" formControlName="currentPeriod" [(ngModel)]="region.customers[i].currentPeriod"/></td>
            <td><input type="text" formControlName="previousPeriod" [(ngModel)]="region.customers[i].previousPeriod"></td>
          </tr>
        </tbody>
      </table>
      </div> <!-- end: div FormArrayName -->
    </form>

Component.ts

export class AppComponent  implements OnInit {

  regionId: number = 5;
  region: RegionModel;
  regionFormGroup: FormGroup;

  constructor( private customerService: CustomerService,private fb: FormBuilder) {  }

  ngOnInit(): void {

    // initialize form
    this.regionFormGroup = new FormGroup({
      regionName: new FormControl(''),
      customersArray: new FormArray([])
    });

    // Retrieve data from datasource
    this.customerService.getCustomerByRegion(5)
      .subscribe( (reg: RegionModel )  => {
        this.region = reg;
        this.buildForm();
      });
  }

  buildForm = () : void => {

    const customersControls = <FormArray>this.regionFormGroup.controls['customersArray'];

    this.region.customers.forEach( (cust : CustomerModel) => {
      customersControls.Push(this.createCustomerFormGroup(cust));
       console.log(customersControls);
    });
  }

  createCustomerFormGroup(cust: CustomerModel) {

        return this.fb.group({
            currentPeriod: [''],
            previousPeriod: ['']
        });
    }
}
12
ClaytonK