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),
});
}
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.
It throws error because you don't have a variable called username
or password
.
In order to solve this, you could either:
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>
AbstractControl#get
to grab the control:HTML:
<div
*ngIf="formGroup.get('username').invalid" class="alert alert-danger"
>
username is required
</div>
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With