问题
I have an API that returns the data something like but the class is same but number of entries changes.
HTML file:
<div class="col-12 col-md-6" formArrayName="plans">
<div class="form-check"
*ngFor="let plan of plans; index as i" [formGroupName]="i">
<label class="form-check-label fw7 h5 mb0">
<input class="form-check-input" type="checkbox" formControlName="checkbox">
{{plan.planCode}}
</label>
<label *ngIf="plan.divisions.length > 0">
Divisions
<select class="form-control" formControlName="division">
<option *ngFor="let division of plan.divisions" [value]="division.divisionCode">
{{division.divisionName}}
</option>
</select>
</label>
</div>
</div>
TS file:
public plans: IPlan[] = new Array<Plan>();
public formControls: {
firstNameCtrl: FormControl,
plans: {
checkbox: FormControl;
division: FormControl;
}[]
};
ngOnInit() {
this.restSvc.getData("/api/plan/GetPlanDetails")
.subscribe((data => {
if (!data.errorMessage) {
this.plans = data;
} else {
this.errMsg = data.errorMessage;
}
}), error => {
this.errMsg = "We found some errors. Please review the form and make corrections.";
});
this.formControls = {
firstNameCtrl: this.fb.control('', Validators.required),
plans: this.plans.map((plan, i) => {
const divisionCode = plan.divisions.length > 0
? plan.divisions[0].divisionCode
: '';
return {
checkbox: this.fb.control(i === 0),
division: this.fb.control(divisionCode)
};
})
};
}
I am getting error
Cannot find control with path: 'plans -> 0'
where the plan is getting mapped before the subscribe completes. How to resolve this?
Sample data:
plans = [
{ planCode: "B3692", divisions: [] },
{ planCode: "B3693", divisions: [] },
{ planCode: "B67",
divisions: [
{ divisionCode: "2", divisionName: "Assisted Living " },
{ divisionCode: "1", divisionName: "LILC" }]
},
{ planCode: "B69",
divisions: [
{ divisionCode: "3", divisionName: "Four Seasons" },
{ divisionCode: "2", divisionName: "Lakeside" },
{ divisionCode: "1", divisionName: "Sunrise" } ]
}
];
回答1:
You need to build your form after your service returns the data.
Think of your ngOnInit
function in steps.
- Request data
- Build form
- Build form array from empty
plans
array - HTML is built
...
- Service returns data
- Update
plans
array - HTML is updated
You now have a situation where *ngFor="let plan of plans"
is creating a block of HTML for each plan
, but you haven't added any form controls to your form.plans
array. So when the form tries to bind to the first form control in form.plans
, it doesn't find anything and breaks.
How to solve this?
The ultimate problem here is that your form array always needs to mirror the model you are building it from, otherwise the difference in array lengths is going to cause problems.
As far as I can tell, there isn't much point in you displaying a partial form while waiting for the service to return the plans. So I would recommend delaying the building of the form until you have all of the data. You would do this by building the form from inside the subscribe.
// no point in initialising with an empty array
plans: IPlan[];
formControls: {
firstNameCtrl: FormControl,
plans: {
checkbox: FormControl;
division: FormControl;
}[]
};
ngOnInit() {
this.restSvc.getData("/api/plan/GetPlanDetails").subscribe(plans => {
if (!plans.errorMessage) {
this.plans = plans;
this.buildForm();
} else {
this.errMsg = plans.errorMessage;
}
}, error => {
this.errMsg = "We found some errors. Please review the form and make corrections.";
});
}
private buildForm(): void {
this.formControls = {
firstNameCtrl: this.fb.control('', Validators.required),
plans: this.plans.map((plan, i) => {
const divisionCode = plan.divisions.length > 0
? plan.divisions[0].divisionCode
: '';
return {
checkbox: this.fb.control(i === 0),
division: this.fb.control(divisionCode)
};
})
};
// TODO: build the form here
}
You will now need to control when your form is added to the DOM, as you won't have a form for it to bind to when it is initially built.
<form *ngIf="form" [formGroup]="form">
<!-- the form -->
</form>
来源:https://stackoverflow.com/questions/60677297/cannot-find-control-with-path-plans-0