angular-cli: Property 'controls' does not exist on type 'AbstractControl'.

Bug Report or Feature Request (mark with an x)

- [x] bug report -> please search issues before submitting
- [ ] feature request

Versions.

@Angular/cli: 1.0.1 node: 7.5.0 os: win32 x64 Windows (10)

Repro steps.

Running the application using ng serve works fine.

using ng build works fine.

when using ng build --prod --aot or ng build --prod I get the error.

It points back to this html file and the controls property??

<div formArrayName="Data">
    <div class="form-group" *ngFor="let field of form.get('Data').**controls**; let i = index">
        <div [formGroupName]="i">
            <div class="col-sm-2">
                <input type="text" class="form-control input-sm text-right" placeholder="Key" formControlName="Name" />
            </div>
            <div class="col-sm-6">
                <input type="text" class="form-control input-sm" placeholder="Value" formControlName="Data" autocomplete="off" />
            </div>
            <div class="col-sm-1">
                <i class="fa fa-trash-o cursor remove-field" title="Remove field" (click)="removeField(i)"></i>
            </div>
        </div>
    </div>
</div>

The log given by the failure.

ERROR in ng:///C:/Angular/lanes4/src/app/containers/edit-user.component.html (34,13): Property ‘controls’ does exist on type ‘AbstractControl’.

Desired functionality.

I would like to build it using --prod and --aot

Mention any other details that might be useful.

Happened since updating to version 4.0.0, i’ve just been using ng build

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 36
  • Comments: 37 (1 by maintainers)

Commits related to this issue

Most upvoted comments

Got it!

Looked at the docs - FormArray

The FormArray class contains the controls property.

get formData() { return <FormArray>this.passwordForm.get('Data'); }

Thanks @Thisen, without you help it would’ve taken longer.

so, my issue was solved by changing the way controls were referenced in my <md-hint> blocks

changed to form['controls'].passwords['controls'].confirmPassword.dirty.

can anyone expand one why this is necessary with forms? is it because of the change detection cycle? I find it quite curious that the error was only ocurring on one of my form when the pattern I was using was consistent all forms…

change: myForm.get('some_items').controls

to: myForm.get('some_items')['controls'];

worked for me when using --prod

Can be fixed by giving your component a get method: get formData { return this.form.get('Data'); } and then in your template: <div class="form-group" *ngFor="let field of formData.controls; let i = index">

La solucion mas facil es: formGroup.controls[‘any’][‘controls’].

In my case only ng build --prod --aot was failing with Property 'controls' does not exist on type 'AbstractControl'

I changed

<div *ngFor="let arr_item of myForm.controls['some_items'].controls;let indx=index;let lst=last;" class="input-group"> 

to

<div *ngFor="let js_arr_item of getControls(myForm, 'some_items');let indx=index;let lst=last;" class="input-group">

&

getControls(frmGrp: FormGroup, key: string) {
  return (<FormArray>frmGrp.controls[key]).controls;
}

turns out, its yet another “cast” issue (pun intended) 😉

This problem still present. If use form.get(‘Data’).controls inside *ngFor and run ng build --prod, you will see error: Property ‘controls’ does not exist on type ‘AbstractControl’.

Angular CLI: 1.0.6 Angular: 4.1.3 node: 6.10.3

thnks @zpydee , this solution worked for me: i used myForm[‘controls’].links[‘controls’] instead of myForm.controls.links.controls

What works for me (even using --prod flag) is, instead of using controls in the FormArray I use value: *ngFor="let item of myForm.get('items').value"

use safe navigation operator ? change: myForm.get('myField').controls

to: myForm.get('myField')?.controls

Running Angular 5.2.3 and was having the same problem. I have a nested FormGroup i.e.

// simplified
this.deviceForm = this.formBuilder.group({
  deviceName: '',
  advancedOptions: this.formBuilder.group({
    bridgeUrl: 'wss://api.my.site:443',
  }),
})
// this.deviceForm: FormGroup
// this.deviceForm.controls.advancedOptions: AbstractControl
// ^^ should really be type FormGroup
// this.deviceForm.controls.advancedOptions.controls.bridgeUrl
// ^^ ERROR 'controls' doesn't exist on type 'AbstractControl'

I found a few ways to get around this (thanks to y’all posting here). Assuming we have:

this.deviceForm.controls.advancedOptions.controls.bridgeUrl

We can:

1. Use .get():

this.deviceForm.get('advancedOptions')!.get('bridgeUrl')!
// Note the '!'s to tell TS to assume `get` result is non-null

2. Cast

(<FormGroup> this.deviceForm.controls.advancedOptions).controls.bridgeUrl

3. Use a custom class

// Define AbstractFormGroup
interface AbstractFormGroup extends FormGroup {
  controls: {
    [key: string]: AbstractControl & FormGroup & AbstractFormGroup,
  }
}
export class ... {
  deviceForm: AbstractFormGroup
}

// Note: This makes nested form groups (a.controls.b.controls.c... etc.)
// acceptable by the compiler, however this exposes both AbstractControl
// and FormGroup properties on all controls, so you can hit runtime errors
// if you try to use FormGroup properties when your control is just an
// AbstractControl and vice versa.

I ended up going with 1 as I think it’s the cleanest

Что работает для меня (даже используя флаг --prod), вместо использования элементов управления в FormArray я использую значение : *ngFor="let item of myForm.get('items').value"

Спасибо!!! Всё работает!!!

Please reopen the issue still occurs in Angular 5.2.0

CLI doesn’t complain when ['controls'] property accessor is used.

Below worked for me

 <div formArrayName="formArray" *ngFor="let item of form.get('formArray')['controls']; let i = index;">
....

</div>

Why is this issue closed? Is this fixed in production builds now? Doesn’t seem like it…

I can confirm this.

when using --prod the HTML fails:

Property ‘controls’ does not exist on type ‘AbstractControl’.

For now, I’m usin workaround of passing the logic to the ts, but it’s not good because it’s a public method.

I’m experiencing the same issue when trying to run ng build --prod with the snippet below although it seems my circumstance is a bit different. Not seeing this occur on any of my other forms?

Can either of your offer any guidance? I’m also running 4.0.0.

<form id="reset-password-form" novalidate [formGroup]="form" (ngSubmit)="submitForm()">
  <div fxLayout fxLayoutWrap>
    <!-- Current Password -->
    <div fxFlex="50%" fxFlex.xs="100%">
      <md-input-container id="currentPassword-container" class="full-width">
        <md-placeholder>Current Password</md-placeholder>
        <input id="currentPassword" mdInput required type="password" formControlName="currentPassword">
        <md-hint align="end" *ngIf="form.controls.currentPassword.dirty && form.controls.currentPassword.errors?.required">Current password is required</md-hint>
        <md-hint align="end" *ngIf="form.controls.currentPassword.dirty && form.controls.currentPassword.errors?.pattern">Must contain 8-16 characters, letters and numbers and symbols</md-hint>
      </md-input-container>
    </div>
    <div fxFlex="50%" fxFlex.xs="100%"></div>
    <div fxFlex="100%" fxLayout fxLayoutWrap formGroupName="passwords">
      <!-- New Password -->
      <div fxFlex="50%" fxFlex.xs="100%">
        <md-input-container id="password-container" class="full-width">
          <md-placeholder>New Password</md-placeholder>
          <input id="password" mdInput required type="password" formControlName="password">
          <md-hint align="end" *ngIf="form.controls.passwords.controls.password.dirty && form.controls.passwords.controls.password.errors?.required">New password is required</md-hint>
          <md-hint align="end" *ngIf="form.controls.passwords.controls.password.dirty && form.controls.passwords.controls.password.errors?.pattern">Must contain 8-16 characters, letters and numbers and symbols</md-hint>
        </md-input-container>
      </div>
      <div fxFlex="50%" fxFlex.xs="100%"></div>
      <!-- Confirm Password -->
      <div fxFlex="50%" fxFlex.xs="100%">
        <md-input-container id="confirmPassword-container" class="full-width">
          <md-placeholder>Confirm New Password</md-placeholder>
          <input id="confirmPassword" mdInput required type="password" formControlName="confirmPassword">
          <md-hint align="end" *ngIf="form.controls.passwords.controls.confirmPassword.dirty && form.controls.passwords.controls.confirmPassword.errors?.required">Password confirmation is required</md-hint>
          <md-hint align="end" *ngIf="form.controls.passwords.controls.confirmPassword.dirty && !form.controls.passwords.controls.confirmPassword.errors?.required &&form.controls.passwords.errors?.passwordMismatch">Passwords do not match</md-hint>
        </md-input-container>
      </div>
      <div fxFlex="50%" fxFlex.xs="100%"></div>
    </div>
  </div>
  <div fxLayout fxLayoutAlign="center">
    <!--Action buttons-->
    <button md-raised-button type="submit" [disabled]="!form.valid">RESET PASSWORD</button>
  </div>
</form>
ERROR in ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (22,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (22,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (22,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (23,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (23,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (23,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (32,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (32,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (32,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (33,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (33,11): Property 'controls' does not exist on type 'AbstractControl'.
ng:///usr/mystique/src/app/features/main/core-features/user-settings/reset-password/reset-password.component.html (33,11): Property 'controls' does not exist on type 'AbstractControl'.

Did the same as @leandrodiniz and it also worked with --env=prod --aot.