Can't acces FormControl instance directly. Cannot read property 'invalid' of undefined

Julius Dzidzevičius picture Julius Dzidzevičius · Jun 16, 2017 · Viewed 26.9k times · Source

Can not acces it in the same way as in Angular docs, so must grab the FormGroup instance first and find FormControl instance in there.. I wonder why? This example works:

<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
  <div class="form-group">
    <label for="username">Username</label>
    <input 
      type="text"
      name="username"
      class="form-control"
      formControlName="username"
    >
    <div *ngIf="myForm.controls.username.invalid" class="alert alert-danger">
      username is required
    </div>
  </div>

While this throws error (difference between these only in *ngIf statement):

<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
  <div class="form-group">
    <label for="username">Username</label>
    <input 
      type="text"
      name="username"
      class="form-control"
      formControlName="username"
    >
    <div *ngIf="username.invalid" class="alert alert-danger">
      username is required
    </div>
  </div>

Cannot read property 'invalid' of undefined

form.component:

import {Component} from '@angular/core';
import {FormGroup, FormControl, Validators} from '@angular/forms';

@Component({
  selector: 'sign-up',
  templateUrl: 'app/sign-up.component.html'
})

export class SignUpComponent {

  myForm = new FormGroup({
    username: new FormControl('username', Validators.required),
    password: new FormControl('', Validators.required),
  });
}

Answer

developer033 picture developer033 · Jun 17, 2017

It throws error because you don't have a variable called username or password.

In order to solve this, you can do the following:

export class SignUpComponent implements OnInit {

  myForm: FormGroup;
  usernameCtrl: FormControl;
  passwordCtrl: FormControl;

  ngOnInit() {
    this.usernameCtrl = new FormControl('username', Validators.required);
    this.passwordCtrl = new FormControl('', Validators.required);

    this.myForm = new FormGroup({
      username: this.usernameCtrl,
      password: this.passwordCtrl
    });
  }
}

... or using FormBuilder:

export class SignUpComponent implements OnInit {

  myForm: FormGroup;
  usernameCtrl: FormControl;
  passwordCtrl: FormControl;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.usernameCtrl = this.formBuilder.control('username', Validators.required);
    this.passwordCtrl = this.formBuilder.control('', Validators.required);

    this.myForm = this.formBuilder.group({
      username: this.usernameCtrl,
      password: this.passwordCtrl
    });
  }
}

Now you can use it directly in template, like this:

<div class="alert alert-danger" *ngIf="usernameCtrl.invalid">
  username is required
</div>

Also, if you prefer you can use [formControl] instead of formControlName:

<input 
  type="text"
  name="username"
  class="form-control"
  [formControl]="usernameCtrl">

PLUNKER