I know it's been asked but I seem to have it set up right and still have an error with my angular form.
Cannot find control with path: 'builderPreferences -> idx -> groupId' and Cannot find control with path: 'builderPreferences -> idx -> manufacturerId'
I have the form group and array builder in TS as such:
@Component({
selector: 'app-builder-detail',
templateUrl: './builder-detail.component.html',
styleUrls: ['./builder-detail.component.scss']
})
export class BuilderDetailComponent implements OnInit {
builderId?: number;
groups?: any[];
manufacturers?: any[];
builder = this.formBuilder.group({
name: ['', Validators.required],
builderPreferences: this.formBuilder.array([]),
});
get builderPreferences(): UntypedFormArray {
return this.builder.get('builderPreferences') as UntypedFormArray;
}
deletePreference(index: number) {
this.builderPreferences.removeAt(index);
}
constructor(
@Optional() @Inject(API_VERSION) private apiVersion: string,
public modalRef: BsModalRef,
private formBuilder: UntypedFormBuilder,
private buildersApiService: BuildersApiService,
private groupsApiService: GroupsApiService,
private manufacturersApiService: ManufacturersApiService,
private loader: LoadingService
) {}
ngOnInit() {
if (this.builderId) this.loadDetail();
}
async loadDetail() {
let builder = await this.buildersApiService.Get({
path: {
version: this.apiVersion,
id: this.builderId ?? 0
}
}).toPromise();
this.builder.patchValue(builder);
if (builder.builderPreferences) {
let processedPreferences = this.formBuilder.array([]);
for (let idx = 0; idx < builder.builderPreferences.length; idx++) {
processedPreferences.push(this.formBuilder.group(builder.builderPreferences[idx]))
}
this.builder.setControl('builderPreferences', processedPreferences);
}
}
newPreference() {
this.builderPreferences.push(this.formBuilder.group({
groupId: [],
manufacturerId: [],
}));
}
async save(close: boolean = false) {
this.loader.start();
let call;
if (this.builderId) {
call = await this.buildersApiService.Update({
body: this.builder.value,
path: {
version: this.apiVersion,
id: this.builderId ?? 0
}
}).toPromise();
} else {
call = await this.buildersApiService.Create({
body: this.builder.value,
path: {version: this.apiVersion}
}).toPromise();
}
this.builder.markAsPristine();
this.loader.stop();
if (!this.builderId) this.builderId = call.id;
}
}
And the html file is as such:
<form autocomplete="off" [formGroup]="builder">
<div class="col-md-12">
<div class="row g-3">
<div class="col-12">
<label class="form-label" for="name">Name</label>
<input formControlName="name" id="name" type="text" class="form-control">
</div>
</div>
<div class="section back-charges">
<h4>Preferences</h4>
<ul class="amount-list" *ngIf="builderPreferences?.length"
formArrayName="builderPreferences" >
<li *ngFor="let builderPreference of builderPreferences.controls; let idx = index">
<div class="row g-3" formGroupName="idx">
<div class="col-3">
<select formControlName="groupId" class="form-control mb-3">
<option value="undefined" selected>Select Group</option>
<option *ngFor="let group of groups"
value="{{ group.id }}">
{{ group.name }}
</option>
</select>
</div>
<div class="col-3">
<select formControlName="manufacturerId" class="form-control mb-3">
<option value="undefined" selected>-- Select Manufacturer / Division --
</option>
<option *ngFor="let manufacturer of manufacturers"
value="{{ manufacturer.id }}">
{{ manufacturer.name }}
</option>
</select>
</div>
<div class="col-1">
<button type="button" name="delete" class="btn btn-text"
(click)="deletePreference(idx)">
<i class="fa fa-trash"></i>
</button>
</div>
</div>
</li>
</ul>
<button class="btn btn-link" type="button" (click)="newPreference()">
<i class="fa fa-plus"></i> Add Preference
</button>
</div>
</div>
</form>
Found the error when looking at this link - looks like I was missing some binding!
swapped the ul from formArrayName to [formArrayName]
<ul class="amount-list" *ngIf="builderPreferences?.length"
[formArrayName]="builderPreferences" >
and the option to this:
<option *ngFor="let group of groups"
[ngValue]="group.id">
{{ group.name }}
</option>