Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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),
  });
}
like image 204
Julius Dzidzevičius Avatar asked Jun 16 '17 12:06

Julius Dzidzevičius


People also ask

How do you access value from FormControl?

To fetch the value of a form control, we have to use value property on the instance of FormControl in our class. In the same way we can fetch the value in HTML template.


2 Answers

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

like image 102
developer033 Avatar answered Sep 22 '22 14:09

developer033


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

like image 38
Javier Rojano Avatar answered Sep 23 '22 14:09

Javier Rojano