I am trying a nested reactive form in Angular 4. It is working fine but when I try to build AOT it's throwing the error
'controls' does not exist on type 'AbstractControl'
I googled and tried few things but no luck. Could anyone tell me how to fix this issue?
<div [formGroup]="myForm"> <div formArrayName="addresses"> <div *ngFor="let address of myForm.get('addresses').controls; let i=index"> <span *ngIf="myForm.get('addresses').length > 1" (click)="removeAddress(i)">Remove</span> <div [formGroupName]="i"> <mat-form-field> <input matInput formControlName="city" placeholder="city" value=""> </mat-form-field> </div> </div> </div> <a (click)="addAddress()"> Add +</a>
</div>typescript code below
constructor(private _fb: FormBuilder) {
}
ngOnInit() { this.myForm = this._fb.group({ addresses: this._fb.array([ this.initAddress(), ]) });
}
initAddress() { return this._fb.group({ city: [''] });
}
addAddress() { const control = <FormArray>this.myForm.get('addresses'); control.push(this.initAddress());
}
removeAddress(i: number) { const control = <FormArray>this.myForm.get('addresses'); control.removeAt(i);
} 8 7 Answers
Based on @Günter Zöchbauer comments , first i changed
myForm.controls['addresses'] to myForm.get('addresses') in both html and typescript
and then based on @yuruzi comment
changed myForm.get('addresses').controls to myForm.get('addresses')['controls']
Its working fine now. Thanks @gunter & yuruzi
4You can fix it easily though. Outsource the "get the controls" logic into a method of your component code (the .ts file):
getControls() { return (this.recipeForm.get('controlName') as FormArray).controls;
}In the template, you can then use:
*ngFor="let ingredientCtrl of getControls(); let i = index"This adjustment is required due to the way TS works and Angular parses your templates (it doesn't understand TS there).
3Change myForm.get('addresses').controls to myForm.get('addresses').value will also fix the issue.
As an update to @sunny kashyap solution, I would write it this way:
getControls() { return (this.recipeForm.get('controlName') as FormArray).controls;
} for validation errors use...
<span *ngIf="f.YOUR_FORM_KEY.controls.YOUR_FORM_KEY.errors?.YOUR_FORM_VALIDATION">YOUR_FORM_KEY is YOUR_FORM_VALIDATION</span>eg.
<span *ngIf="f.name.controls.name.errors?.required">Name is required</span>ts file
get f(): any { return this.userForm.controls;
} to get the length of a FormArray , use simply length :
<span *ngIf="myForm.controls['addresses'].length > 1" (click)="removeAddress(i)">Remove</span>Hope it helps
3Can use a custom interface
// Define AbstractFormGroup
export interface AbstractFormGroup extends FormGroup { controls: { [key: string]: AbstractFormGroup & AbstractFormGroup[] & AbstractControl & FormGroup & FormArray, }
}
// Usage example
class ... { myForm: AbstractFormGroup ... this.myForm = this.fb.group({...}) as AbstractFormGroup
}