I am trying to iterate over a formArray in my component but I get the following error
Error: Cannot find control with unspecified name attribute
Here is what the logic looks like on my class file
export class AreasFormComponent implements OnInit { public initialState: any; public areasForm: FormGroup; constructor(private fb: FormBuilder) { } private area(): any { return this.fb.group({ name: ['', [Validators.required]], latLong: ['', [Validators.required]], details: ['', [Validators.required]] }); } public ngOnInit(): void { this.areasForm = this.fb.group({ name: ['', [Validators.required]], areas: this.fb.array([this.area()]) }); } } and my template file
<form [formGroup]="areasForm" (ngSubmit)="onSubmit(areasForm.values)"> <md-input-container> <input mdInput placeholder="Location Name" type="text" formControlName="name" required> <md-error *ngIf="areasForm.get('name').hasError('required')">Please enter the locationName</md-error> </md-input-container> <md-grid-list cols="1" [formArrayName]="areas"> <md-grid-tile formGroupName="i" colspan="1" rowHeight="62px" *ngFor="let area of areasForm.controls.areas.controls; let i = index "> <md-grid-list cols="3" rowHeight="60px"> <md-grid-tile colspan="1"> <md-input-container> <input mdInput placeholder="Area Name" type="text" formControlName="name" required> <md-error *ngIf="areasForm.get('areas').controls[i].name.hasError('required')">Please enter the area name</md-error> </md-input-container> </md-grid-tile> <md-grid-tile colspan="1"> <md-input-container> <input mdInput placeholder="details" type="text" formControlName="details" required> <md-error *ngIf="areasForm.get('areas').controls[i].name.hasError('required')">Please enter the locationName</md-error> </md-input-container> </md-grid-tile> <md-grid-tile colspan="1"> <button md-fab (click)="remove(i)"><md-icon>subtract</md-icon>Remove Area</button> </md-grid-tile> </md-grid-list> </md-grid-tile> </md-grid-list> <button type="submit" [disabled]="areasForm.invalid" md-raised-button color="primary">Submit</button> </form> 11 Answers
Remove the brackets from
[formArrayName]="areas" and use only
formArrayName="areas" This, because with [ ] you are trying to bind a variable, which this is not. Also notice your submit, it should be:
(ngSubmit)="onSubmit(areasForm.value)" instead of areasForm.values.
In my case I solved the issue by putting the name of the formControl in double and sinlge quotes so that it is interpreted as a string:
[formControlName]="'familyName'" similar to below:
formControlName="familyName" 1The problem for me was that I had
[formControlName]="" Instead of
formControlName="" 1Instead of
formGroupName="i" You must use:
[formGroupName]="i" Tips:
Since you're looping over the controls, you've already the variable area, so you can replace this:
*ngIf="areasForm.get('areas').controls[i].name.hasError('required')" by:
*ngIf="area.hasError('required', 'name')" 1For me, I was trying to add [formGroupName]="i" and/or formControlName and forgetting to specify the parent formArrayName. Pay attention to your form group tree.
This was happening for me because I had fromArrayName instead of formArrayName somewhere 😑
So, I had this code:
<div *ngIf="contentData"> <button mat-stroked-button [disableRipple]="true" (click)="openSelect()" [ngClass]="{'only-icon': !contentData?.buttonText?.length}"> <i *ngIf="contentData.iconClassInfo"></i> <span *ngIf="contentData.buttonText">{{contentData.buttonText}}</span> </button> <mat-select [formControl]="theFormControl" #buttonSelect (selectionChange)="onSelect(buttonSelect.selected)" (click)="$event.stopPropagation();"> <mat-option *ngFor="let option of options" [ngClass]="{'selected-option': buttonSelect.selected?.value === option[contentData.optionsStructure.valName]}" [disabled]="buttonSelect.selected?.value === option[contentData.optionsStructure.valName] && contentData.optionSelectedWillDisable" [value]="option[contentData.optionsStructure.valName]"> {{option[contentData.optionsStructure.keyName]}} </mat-option> </mat-select> </div> Here I was using standalone formControl, and I was getting the error we are talking about, which made no sense for me, since I wasn't working with formgroups or formarrays... it only disappeared when I added the *ngIf to the select it self, so is not being used before it actually exists. That's what solved the issue in my case.
<mat-select [formControl]="theFormControl" #buttonSelect (selectionChange)="onSelect(buttonSelect.selected)" (click)="$event.stopPropagation();" *ngIf="theFormControl"> <mat-option *ngFor="let option of options" [ngClass]="{'selected-option': buttonSelect.selected?.value === option[contentData.optionsStructure.valName]}" [disabled]="buttonSelect.selected?.value === option[contentData.optionsStructure.valName] && contentData.optionSelectedWillDisable" [value]="option[contentData.optionsStructure.valName]"> {{option[contentData.optionsStructure.keyName]}} </mat-option> </mat-select> 1This happened to me because I left a formControlName empty (formControlName=""). Since I didn't need that extra form control, I deleted it and the error was resolved.
Only WinMerge made me find it (by comparison with a version that works). I had a case problem on formGroupName. Brackets around this word can lead to the same problem.
I had accidentally entered the control name when creating the formGroup:
getFormGroup(dataItem: any): FormGroup { return new FormGroup({ 'Id': new FormControl(dataItem != null ? dataItem.Id : ''), 'PsDepartmentId': new FormControl(dataItem != null ? dataItem.DepartmentId : '', Validators.required), //Accidentally used 'DepartmentId' on this line 'IsActive': new FormControl(dataItem != null ? dataItem.IsActive : true) }); } Then it failed in the html when I did
<kendo-dropdownlist [data]="psDepartments" textField="ConCatedName" valueField="Id" [formControl]="formGroup.get('DepartmentId')" [valuePrimitive]="true"> </kendo-dropdownlist> For me, the issue was I was missing the field name in the form builder:
return this.fb.group({ name: ['', [Validators.required]], latLong: ['', [Validators.required]], details: ['', [Validators.required]], // missing field name! });