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
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">
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: ['']
});
}
}