Julius Dzidzevičius
Julius Dzidzevičius

Reputation: 11000

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

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),
  });
}

Upvotes: 17

Views: 32761

Answers (7)

kc12
kc12

Reputation: 11

Another option is to check if username is defined, replacing the following

HTML:
<div *ngIf="username.invalid" class="alert alert-danger">

with the following, should also work

HTML:
<div *ngIf="username !== undefined && username.invalid" class="alert alert-danger">

Upvotes: 0

developer033
developer033

Reputation: 24874

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

In order to solve this, you could either:

  1. Store the control in a component variable:

TS:

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent {
  readonly usernameCtrl = this.formBuilder.control('username', Validators.required);
  readonly passwordCtrl = this.formBuilder.control('', Validators.required);
  readonly formGroup = this.formBuilder.group({
    username: this.usernameCtrl,
    password: this.passwordCtrl
  });

HTML:

<div 
  *ngIf="userNameCtrl.invalid" class="alert alert-danger"
>
  username is required
</div>
  1. Use AbstractControl#get to grab the control:

HTML:

<div 
  *ngIf="formGroup.get('username').invalid" class="alert alert-danger"
>
  username is required
</div>
  1. Use AbstractControl#hasError so you'll be able to specify different messages for each existent validation:

HTML:

<div 
  *ngIf="formGroup.hasError('required', 'username')" class="alert alert-danger"
>
  username is required
</div>

DEMO

Upvotes: 26

Denz Ulita
Denz Ulita

Reputation: 11

actually I'm just new in Angular, I'm just using it for a month and also searching for some answers hehe but in your Component add a getter like this:

export class SignUpComponent {

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

get username(){
  return this.myForm.controls['username'];
}

}

Upvotes: 1

Sachini Witharana
Sachini Witharana

Reputation: 116

In the ts file add:

get username() { return this.myForm.get('username'); }
get password() { return this.myForm.get('password'); } }

Upvotes: 1

Mickey
Mickey

Reputation: 21

I had the same problem, I add 'this' to "myForm.controls....".It helped me.

Instead of:

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

Do:

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

Hope this helped you.

Upvotes: 1

Alexey Volynshchikov
Alexey Volynshchikov

Reputation: 157

For me works:

form.component:

getFormControl(name) {
    return this.Form.get(name);
}

template:

<input 
  type="text"
  name="username"
  class="form-control"
  formControlName="username"
>
<div *ngIf="getFormControl('username').invalid" class="alert alert-danger">
  username is required
</div>

Upvotes: 6

Javier Rojano
Javier Rojano

Reputation: 982

You can solve this issue using a Form Group and defining the corresponding getters in your controller. In order to achieve this goal:

In the controller:

1) Remove the form control variables definition and initialization

usernameCtrl: FormControl;
passwordCtrl: FormControl;
...
this.usernameCtrl = this.formBuilder.control('username',Validators.required);
this.passwordCtrl = this.formBuilder.control('', Validators.required);

2)Change the form group initialization to this

ngOnInit() {
this.myForm = this.formBuilder.group({
  username: ['usename', Validators.required]
  password: ['', Validators.required]
});

}

3) Add the getters

get username() { return this.myForm.get('username'); }
get password() { return this.myForm.get('password'); }

In the template:

1) add a parent div with [formGroup]="MyForm"

<div [formGroup]="myForm">
...
</div>

2) change [formControl]="usernameCtrl" for forcontrolName=username and *ngIf="usernameCtrl.invalid" for *ngIf="username.invalid"

<input type="text"
       name="username"
       class="form-control"
       formControlName="username">
  <div *ngIf="username.invalid" class="alert alert-danger"> 
    username is required
  </div>

3) change [formControl]="passwordCtrl" for forcontrolName=password and *ngIf="passwordCtrl.invalid" for *ngIf="password.invalid" te.

<input type="text"
       name="password"
       class="form-control"
       formControlName="password">
  <div *ngIf="password.invalid" class="alert alert-danger">
    password is required
  </div>

Plunker

Upvotes: 11

Related Questions