Property 'controls' does not exist on type 'AbstractControl' Angular 4 [duplicate]
Asked Answered
A

7

138

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);
}
Algoid answered 25/10, 2017 at 7:13 Comment(8)
I think the preferred way is myForm.get('addresses')Tar
@GünterZöchbauer do we need to use this in HTML ngFor or in the Typescript ?Algoid
Should work in both if myForm is an AbstractControlTar
@GünterZöchbauer updated code in the question as per ur suggestion, its working fine but AOT throw same error :( any idea ? pls chk codeAlgoid
Then you probably changed it on the wrong place. It's quite unlikely that get() throws an error that controls() doesn't exist.Tar
create getter like get addressesControls() { return (<FormArray>this.myForm.get('addresses')).controls; } or just use the following myForm.get('addresses')['controls']Carnahan
@Carnahan Thanks just update myForm.get('addresses')['controls'] in HTML , its working fine nowAlgoid
how this thing will itterate may I know Munna rentalPricingForm.controls.pricingBundle.controls[i].controls.packageName.errorsCindy
A
276

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

Algoid answered 25/10, 2017 at 9:3 Comment(4)
My case: form.get('user')['controls'].profile. its ok tnksElizabethelizabethan
This wrked for me seamlessly. Thanks Man! In the tempate myForm.get('addresses')['controls'] In the ts const control = this.myForm.controls.addresses as FormArrayTincher
Kinda woodoo magic, it must be working without array notation....Disability
I think @sunnykashyap's answer is preferred by keeping type safety in place. This way sets the type to 'any' which can still generate type errors (Element implicitly has an 'any' type because expression of type '"controls"' can't be used to index type 'AbstractControl<any, any>')Beefwitted
H
119

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).

Hurff answered 18/12, 2018 at 8:6 Comment(2)
Maybe on later angular versions you have to use return (this.recipeForm.get('controlName') as FormArray).controls;Cristionna
Works Well with Angular 14Acanthaceous
L
13

Change myForm.get('addresses').controls to myForm.get('addresses').value will also fix the issue.

Labroid answered 3/10, 2018 at 14:30 Comment(0)
S
12

As an update to @sunny kashyap solution, I would write it this way:

getControls() {
  return (this.recipeForm.get('controlName') as FormArray).controls;
}
Sociology answered 9/5, 2019 at 20:38 Comment(0)
P
2

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;
}
Pyre answered 9/3, 2019 at 1:24 Comment(0)
P
0

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

Peppy answered 25/10, 2017 at 8:24 Comment(3)
Thanks. But It doesn't fix issue.Algoid
Yes @mohammed, pls chk the updated code in questionAlgoid
can you please try this let address of myForm.controls.addresses.controls instead of let address of myForm.get('addresses').controlsPeppy
C
0

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
}
Countervail answered 29/10, 2019 at 19:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.