angular: Property 'controls' does not exist on type 'AbstractControl'

I’m submitting a

[x] bug report

Current behavior As there’s no clean access to the FormGroup’ controls, currently there’s a ng build -prod error related to types when you try to access the .controls property, and AbstractControl does not have that property:

ERROR in ng:///path/to/app/my/custom.component.html (7,10): Property 'controls' does not exist on type 'AbstractControl'.

https://github.com/angular/angular/blob/4.0.0/packages/forms/src/model.ts#L834

where I have a form with subgroups like:

this.inputForm = this._builder.group({
  base: this._builder.group({
    monthly: [
      '', Validators.compose([Validators.required, Validators.pattern(regInt)])
    ],
   ...
  }),
  user: this._builder.group({
    ...
  })
});

and perform template-driven validations per row like:

<div class="form-group row" [ngClass]="{'has-danger': inputForm.controls.base.controls.monthly.dirty && !inputForm.controls.base.controls.monthly.valid}">
  <label class="col-4 col-form-label" for="inp-monthly">
    Monthly Expenses
  </label>
  <div class="col-8">
    <div class="input-group">
      <span class="input-group-addon" id="inp-monthly-s">$</span>
      <input class="form-control" id="inp-monthly" formControlName="monthly" aria-describedby="inp-monthly-s"
        type="number" min="1" placeholder="Add up all your costs (rent, salary, telephone, internet, inventory costs, etc)" />
    </div>
    <div class="form-control-feedback" [hidden]="inputForm.controls.base.controls.monthly.pristine || inputForm.controls.base.controls.monthly.valid">
     Please enter a quantity.
    </div>
  </div>
</div>

Expected behavior ng build -prodto compile without Type errors.

Minimal reproduction of the problem with instructions References to this issue are in this ticket: https://github.com/angular/angular/issues/10192#issuecomment-264246375

  • Angular version: 4.0.1 Project built with angular/cli 4.0.0 but packages updated today to 4.0.1

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 16 (2 by maintainers)

Most upvoted comments

@matheo thanks. FormGroup.controls return type is {[key: string]: AbstractControl}. inputForm.controls.base will return AbstractControl. This is why you got an error.

as a workaround use get method: inputForm.get('base.monthly').pristine

I have nested arrays in the same forms, this doesn’t work from me . why it should run on dev and after 2 weeks of development we get this error ?

I’d have to say that @DzmitryShylovich 's workaround for AbstractControl doesn’t work anymore with 4.0.2. I just think that validation for template on dynamic values is totally wrong even for aot, as there is no way to cast a value in template. Please add casting to template or shut that feature off.

Well, issue is closed, but anyway, as FormGroup is the key:

buildForm() {
    let fb = this.formBuilder;

    this.form = fb.group({
        animals: fb.group({
            cat: '',
            dog: '',
            other: ''
        })
    });
}

get animals(): FormGroup {
    return this.form.get('animals') as FormGroup;
}

<div class="button-list" formGroupName="animals">
    <label class="button" *ngFor="let animal of animals.controls | keys" [ngClass]="{'active': form.value.animals[animal]}">
        <input type="checkbox" formControlName="{{animal}}">
        <span class="button__text">{{animal}}</span>
    </label>
</div>

Angular 4.4.3

UPD.

If you omit as FormGroup it will work on development and will not throw any errors. But if you run ng build it will throw you this topic’s error message and stops the build.

Yeah @itsnotvalid is right @DzmitryShylovich 's solution doesn’t work for me. But I found a way, just reference the formArray in typescript:

formGroup: FormGroup;
formArray: FormArray;

initForm() {
  this.formArray = new FormArray([]);

  //init form array here - push FormGroups

 //then insert form array
 this.formBuilder.group({
 forms: formArray;
 });
}

Then just use *ngFor="let form of formArray.controls this way you don’t need casting anymore

@matheo, I meant the “please don’t comment on closed issue.”. It’s difficult enough to follow the angular development here, but if you use the issue-tracker as kind of “chat-support-system”, then things become very difficult.

If you are not sure if something is a bug or not, or if you have questions, there are other resources to ask for help:

https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

.

@matheo , @DzmitryShylovich: maybe you want to exchange some cooking-recipes, too?

result$: BehaviorSubject<ResultState> = new BehaviorSubject<ResultState>(initialResult);