This question already has answers here:
Closed last month.
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"
class="panel panel-default">
<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()" style="cursor: default"> 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);
}
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
You 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).
As an update to @sunny kashyap solution, I would write it this way:
getControls() {
return (this.recipeForm.get('controlName') as FormArray).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
Change myForm.get('addresses').controls
to myForm.get('addresses').value
will also fix the issue.
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;
}
Can 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
}