I'm trying to render a div based on specific errors, my form works but is buggy and is trowing a type error, "undefined is not an object" , and i don't understand why; can someone help me understand what I'm missing? I've tried simplifying my code by using just the .errors propery, that takes the errors away but its not specific enough to so that it knows what error to render depending on the state of the form, any insight would be super helpful :)
HTML
<form [formGroup]="form">
<div class="spacer">
<label for="oldPassword">Old Password</label><br /><input
type="text"
class="form-control"
id="oldPassword"
formControlName="oldPassword"
/>
<div class="alert alert-danger" *ngIf="form.get('oldPassword').errors.passwordValidator">Duplicate Password</div>
<div class="alert alert-danger" *ngIf="form.get('oldPassword').touched && form.get('oldPassword').errors.required">Old Password is Required</div>
<div *ngIf="forms.get('oldPassword').pending">Loading...</div>
</div>
<div class="spacer">
<label for="newPassword">New Password</label><br /><input
type="text"
class="form-control"
id="newPassword"
formControlName="newPassword"
/>
<div *ngIf="form.get('newPassword').touched && newPassword.invalid" class="alert alert-danger">New Password is Required</div>
</div>
<div class="spacer">
<label for="confirmPassword">Confirm Password</label><br /><input
type="text"
class="form-control"
id="confirmPassword"
formControlName="confirmPassword"
/>
<div *ngIf="confirmPassword.touched && confirmPassword.invalid" class="alert alert-danger">Confirm Password is Required</div>
</div>
<button class="btn btn-primary" (click)="onClick()">Submit!</button>
</form>
{{ oldPassword | json}}
TS:
import { Component } from '#angular/core';
import { FormBuilder, Validators, FormGroup, FormControl,} from '#angular/forms'
import { CustomValidators } from '../passwordValidator';
#Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css']
})
export class FormComponent {
form = new FormGroup({
oldPassword: new FormControl('',Validators.required, CustomValidators.passwordValidator),
newPassword: new FormControl('',Validators.required),
confirmPassword: new FormControl('',Validators.required)
})
onClick() {
console.log(this.form.get('oldPassword').errors)
}
}
//CustomValidators.passwordValidator
CUSTOM VALIDATOR.TS
import { AbstractControl, ValidationErrors, } from '#angular/forms';
export class CustomValidators {
static passwordValidator(control: AbstractControl): Promise<ValidationErrors | null> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (control.value === "123") {
resolve({ passwordValidator: true })
}
resolve(null)
}, 2000);
});
}
}
Here is the error
You have some issues...
<div *ngIf="forms.get('oldPassword').pending">Loading...</div>, remove the s from forms
<div *ngIf="confirmPassword.touched && confirmPassword.invalid" is invalid
*ngIf="form.get('newPassword').touched && newPassword.invalid" is invalid
Your custom async validator should be placed as the third argument
Those undefined issues stem from errors being null
Suggestion: Use FormBuilder instead of calling new FormControl(), but I'll keep my sample with your current code. Also usually we use ngSubmit instead of click event in forms.
So first place the async validator in correct place:
oldPassword: new FormControl(
"",
[Validators.required],
[CustomValidators.passwordValidator]
),
The rest of the errors is related to that errors being null in template if there are no errors... where you are calling such as...
*ngIf="form.get('oldPassword').errors.passwordValidator"
You could solve this by adding the safe navigation operator:
*ngIf="form.get('oldPassword').errors?.passwordValidator"
That will work, but I use the following way, which is in my opinion nicer and more intuitive:
*ngIf="form.hasError('passwordValidator', 'oldPassword')"
So here's a stripped down, shortened version of your code:
<form [formGroup]="form" (ngSubmit)="onClick()">
<label for="oldPassword">Old Password</label><br />
<input formControlName="oldPassword" />
<div *ngIf="form.hasError('passwordValidator', 'oldPassword')">
Duplicate Password
</div>
<div *ngIf="form.get('oldPassword').touched && form.hasError('required', 'oldPassword')">
Old Password is Required
</div>
<div *ngIf="form.get('oldPassword').pending">Loading...</div>
<button type="submit" [disabled]="!form.valid">Submit!</button>
</form>
STACKBLITZ
Related
I have this inscription form. I tried to validate it but in vain. inputs are saved in my database despite they are empty I want to have these validations:
All inputs are required
email address should be valid
name should be composer by only letters
Password should have minimum 8 characters, at least 1 uppercase
letter, 1 lowercase letter and 1 number
I want to have a message under evey invalid input.(in <div id="na"></div> for example).How can I do this please?
HTML file
<h2 class="text-center">Inscription</h2>
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-6 col-md-offset-3">
<div class="jumbotron">
<form [formGroup]="angForm" (ngSubmit)="postdata(angForm)" autocomplete="off">
<div class="form-group mb-3">
<label for="name">Nom</label>
<input type="text" name="name" formControlName="name" autocomplete="off" id="name"
class="form-control input-sm" placeholder="Nom">
</div>
<div id="na"></div>
<div class="form-group mb-3">
<label for="email">Email</label>
<input type="email" name="email" formControlName="email" autocomplete="off" id="email"
class="form-control input-sm" placeholder="Email">
</div>
<div id="mail"></div>
<div class="form-group mb-3">
<label for="Password">Mot de passe</label>
<input type="password" name="Password" formControlName="password" autocomplete="off"
id="password" class="form-control input-sm" placeholder="Mot de passe">
</div>
<div id="pwd"></div>
<button type="sumit" class="btn btn-success">Enregistrer</button>
</form>
</div>
</div>
<div class="col-md-3">
</div>
</div>
Type script file
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, FormBuilder, Validators, NgForm } from '#angular/forms';
import { first } from 'rxjs/operators';
import { Router } from '#angular/router';
import { ApiService } from '../api.service';
#Component({
selector: 'app-inscription',
templateUrl: './inscription.component.html',
styleUrls: ['./inscription.component.css']
})
export class InscriptionComponent implements OnInit {
angForm: FormGroup;
constructor(private fb: FormBuilder,private dataService: ApiService,private router:Router) {
this.angForm = this.fb.group({
email: [],
password: [],
name: [],
mobile: []
});
}
ngOnInit() {
}
postdata(angForm1:any){this.dataService.userregistration(angForm1.value.name,angForm1.value.email,angForm1.value.password)
.pipe(first())
.subscribe(
data => {
this.router.navigate(['login']);
},
error => {
});
}
get email() { return this.angForm.get('email'); }
get password() { return this.angForm.get('password'); }
get name() { return this.angForm.get('name'); }
}
thanks in advance
this.angForm = this.fb.group({
email: ['', Validators.required, Validators.email],
password: ['', Validators.required, Validators.minLength(8), Validators.pattern("(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}")],
name: ['', Validators.required, Validators.pattern('^[a-zA-Z ]*$')],
mobile: [null, Validators.required, Validators.minLength(10), Validators.maxLength(10)]
});
This is the syntax for Validations.
In HTML, before closing of form-group div write
<span class="text-danger"
*ngIf="(angForm.name.touched || submitted) &&
angForm.name.errors?.required">
Name is required
</span>
<span class="text-danger"
*ngIf="((angForm.password.touched || submitted) &&
angForm.password.errors?.required )|| (angForm.invalid && submitted)">
Must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters </span>
same applies for email, mobile error msg in HTML.
Please refer for reactive form validation.
https://www.freecodecamp.org/news/how-to-validate-angular-reactive-forms/
response to Rothitha
If you don't want to use the "auxiliar variable" submitted you can use in submit.
submit(form:FormGroup)
{
if (form.invalid)
form.markallAsTouched()
else
{
..doSomething..
}
}
If we can better mannagement about errors (remove this ugly *ngIf="angForm.get('password').touched && angForm.get('password').touched" we can use a tecnica similar bootstrap mannage the error
We use a .css like
.invalid-feedback
{
display:none
}
.ng-invalid.ng-touched ~ .invalid-feedback
{
display: block;
}
And an html like
<!--enclosed all under a div-->
<div>
<!--a label-->
<label for="email">Email</label>
<!--a input-->
<input id="email" formControlName="email">
<!--a div class="invalid-feedback-->
<div class="invalid-feedback">
<!--if there're several validators use *ngIf-->
<div *ngIf="angForm.controls.email.errors?.required">Email is required</div>
<div *ngIf="angForm.controls.email.errors?.email">it's not a valid email</div>
</div>
</div>
See stackblitz
am sending an put request based on these files.
Venue.ts file
export class Venue {
id: number;
venueName: string;
cityName: string;
emailContact: string;
fighter1: string;
fighter2: string;
dateOfFight: Date;
active: boolean;
}
My Angular Component files:
create-venue.component.html
<h3>Create Event</h3>
<div [hidden]="submitted" style="width: 400px;">
<form (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="name">Venue Name</label>
<input type="text" class="form-control" id="venueName" required [(ngModel)]="venue.venueName" name="venueName">
</div>
<div class="form-group">
<label for="name">City Name</label>
<input type="text" class="form-control" id="cityName" required [(ngModel)]="venue.cityName" name="cityName">
</div>
<div class="form-group">
<label for="name">Email Contact</label>
<input type="text" class="form-control" id="emailContact" required [(ngModel)]="venue.emailContact" name="emailContact">
</div>
<div class="form-group">
<label for="name">Fighter 1 Contact</label>
<input type="text" class="form-control" id="fighter1" required [(ngModel)]="venue.fighter1" name="fighter1">
</div>
<div class="form-group">
<label for="name">Fighter 2 Contact</label>
<input type="text" class="form-control" id="fighter2" required [(ngModel)]="venue.fighter2" name="fighter2">
</div>
<div class="form-group">
<label for="name">Choose a time for your Event:</label>
<input type="datetime-local" class="form-control" id="dateOfFight" min="2021-01-01T00:00" max="2023-06-14T00:00" required [(ngModel)]="venue.dateOfFight" name="dateOfFight">
</div>
<button type="submit" class="btn btn-success">Submit</button>
</form>
</div>
<div [hidden]="!submitted">
<h4>You submitted successfully!</h4>
<!-- <button class="btn btn-success" (click)="newVenue()">Add</button> -->
</div>
create-venue.component.ts
import { VenueService } from '../venue.service';
import { Venue} from '../venue';
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-create-venue',
templateUrl: './create-venue.component.html',
styleUrls: ['./create-venue.component.css']
})
export class CreateVenueComponent implements OnInit {
venue: Venue = new Venue();
submitted = false;
constructor(private venueService: VenueService,
private router: Router) {}
ngOnInit() {
}
newVenue(): void {
this.submitted = false;
this.venue = new Venue();
}
save() {
this.venueService.createVenue(this.venue)
.subscribe(data => console.log(data), error => console.log(error));
this.venue = new Venue();
this.gotoList();
}
onSubmit() {
this.submitted = true;
this.save();
}
gotoList() {
this.router.navigate(['/venues']);
}
}
My current sent data in chrome:
I am quite new to javascript and angular, maybe this was answered before but I have no idea how to get the input data into the Venue object...
Edit:
This is my header tab:
I
using a string instead of Date type for the dateOfFight property will let you post to the backend without issue.
You can then generate the date with new Date(datestring) on your server if needed. On the front end you can look into date pipes which will help you format the string accordingly.
You also seem to not be capturing any values in your date input. Notice venue.dateOfFight is not even there. Perhaps try logging out your data before posting
You can use a string instead of date type dateOfFight: string;, and before saving, trasform it into a date format with Moment js.
moment(Date.now()).format('YYYY-MM-DD').toString()
I am trying to write a form that involves the logic of confirming the new password value in a confirm password field. I am almost positive it is something to do with how my logic is rendered in the custom validator itself: password.validators.ts. Without giving the solution up is there something that my logic in the validation function is missing? I have attached my template, customer validator file and component. I would like the confirm password field to throw an error that is stated in my template when my custom validation renders true, this condition would be that the new password field does not match the confirm password field. When I go to enter values in the field nothing shows up.
<form [formGroup]="form">
<div class="form-group">
<label for="oldPassword">Old Password</label>
<input
formControlName="oldPassword"
type="password"
class="form-control"
id="oldPassword"
placeholder="Enter old password">
<div
*ngIf="oldPassword.touched && oldPassword.invalid"
class="alert alert-danger">
<div *ngIf="oldPassword.errors.required">Old password is required</div>
<div *ngIf="oldPassword.errors.cannotContainOldPassword">Old password is not valid</div>
</div>
</div>
<div class="form-group">
<label for="newPassword">New Password</label>
<input
formControlName="newPassword"
type="text"
class="form-control"
id="newPassword"
placeholder="Enter new password">
<div
*ngIf="newPassword.touched && newPassword.invalid"
class="alert alert-danger">
<div *ngIf="newPassword.errors.required">New password is required</div>
</div>
</div>
<div class="form-group">
<label for="confirmPassword">Confirm Password</label>
<input
formControlName="confirmPassword"
type="text"
class="form-control"
id="confirmPassword"
placeholder="Confirm new Password">
<div
*ngIf="confirmPassword.touched && confirmPassword.invalid"
class="alert alert-danger">
<div *ngIf="confirmPassword.errors.required">Confirm password is required</div>
<div *ngIf="confirmPassword.errors.confirmNewPassword">Passwords must match</div>
</div>
</div>
<button type="submit" class="btn btn-primary">Change Password</button>
</form>
import { AbstractControl, ValidationErrors, ValidatorFn, Validators } from '#angular/forms';
export class PasswordValidators{
//Make sure old password is correct
static cannotContainOldPassword(control: AbstractControl) : Promise<ValidationErrors> | null {
return new Promise((resolve, reject) => {
setTimeout(()=>{
if(control.value != "1234"){
resolve({cannotContainOldPassword: true});
}else{
resolve(null);
}
});
});
}
//Make sure passwords match
static confirmNewPassword(control: AbstractControl): ValidationErrors | null{
let newPass = control.get('newPassword');
let confirmPass = control.get('confirmPassword');
if(newPass === confirmPass){
return null;
//return { confirmNewPassword: true };
}else{
return { confirmNewPassword: true };
}
}
}
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup, Validators } from '#angular/forms';
import { PasswordValidators } from './password.validators';
#Component({
selector: 'password-form-change',
templateUrl: './password-form-change.component.html',
styleUrls: ['./password-form-change.component.css']
})
export class PasswordFormChangeComponent {
form = new FormGroup({
oldPassword: new FormControl('', Validators.required, PasswordValidators.cannotContainOldPassword),
newPassword: new FormControl('', Validators.required),
confirmPassword: new FormControl('', [
Validators.required,
PasswordValidators.confirmNewPassword
])
})
get oldPassword(){
return this.form.get('oldPassword');
}
get newPassword(){
return this.form.get('newPassword');
}
get confirmPassword(){
return this.form.get('confirmPassword');
}
}
The problem
The problem is that you are applying the validator to the FormControl itself but inside the Validator, you try to access its children (which a Control does not have).
form = new FormGroup({
oldPassword: new FormControl(''),
newPassword: new FormControl(''),
// Here you apply the Validator to your control
confirmPassword: new FormControl('', [PasswordValidators.confirmNewPassword])
})
static confirmNewPassword(control: AbstractControl): ValidationErrors | null{
// Your control does not have children "newPassword" and "confirmPassword"
let newPass = control.get('newPassword');
let confirmPass = control.get('confirmPassword');
if(newPass === confirmPass) { // You are comparing FormControls instead of their values
return null;
} else {
return { confirmNewPassword: true };
}
}
The solution
The simpliest solution would be to move the validator to the form group instead. This might also be the preferred solution, since your validator will then be run when either "newPassword" or "confirmPassword" change.
First, fix your validator to check the values instead of comparing the Controls themselves:
static confirmNewPassword(control: AbstractControl): ValidationErrors | null{
let newPass = control.get('newPassword').value; // add .value
let confirmPass = control.get('confirmPassword').value; // add .value
return newPass === confirmPass ? null : {confirmNewPassword: true };
}
Then apply the validator to the whole form(group):
form = new FormGroup({
oldPassword: new FormControl(''),
newPassword: new FormControl(''),
// Here you apply the Validator to your control
confirmPassword: new FormControl('')
}, {validators: PasswordValidators.confirmNewPassword}) // Add the validator to the group instead of your control
Finally, adjust your template to check for the error on the form(group) instead of your control:
<div class="form-group">
<label for="confirmPassword">Confirm Password</label>
<input
formControlName="confirmPassword"
type="text"
class="form-control"
id="confirmPassword"
placeholder="Confirm new Password">
<div
*ngIf="confirmPassword.touched && confirmPassword.invalid"
class="alert alert-danger"
>
<div *ngIf="confirmPassword.errors?.required">Confirm password is required</div>
<!-- ^ -->
<!-- Access the errors object by using ?, since errors is null when no error is present -->
<div *ngIf="form.errors?.confirmNewPassword">Passwords must match</div>
<!-- ^^^^ -->
<!-- Check for errors on form here, instead of the control -->
</div>
</div>
Here a Stackblitz with a minimal example on this.
The issue was in the ngIf directive within my template. The problem was that as soon as I typed something into the Confirm Password field, the *ngIf="confirmPassword.touched && confirmPassword.invalid" would render to true hence both the errors under that parent div would go away. So the solution was to take insert another div for the password validation underneath. The "?" operator must be included or else it will throw "ERROR TypeError: Cannot read property 'confirmNewPassword' of null".
<form [formGroup]="form">
<div class="form-group">
<label for="oldPassword">Old Password</label>
<input
formControlName="oldPassword"
type="password"
class="form-control"
id="oldPassword"
placeholder="Enter old password">
<div
*ngIf="oldPassword.touched && oldPassword.invalid"
class="alert alert-danger">
<div *ngIf="oldPassword.errors.required">Old password is required</div>
<div *ngIf="oldPassword.errors.cannotContainOldPassword">Old password is not valid</div>
</div>
</div>
<div class="form-group">
<label for="newPassword">New Password</label>
<input
formControlName="newPassword"
type="text"
class="form-control"
id="newPassword"
placeholder="Enter new password">
<div
*ngIf="newPassword.touched && newPassword.invalid"
class="alert alert-danger">
<div *ngIf="newPassword.errors.required">New password is required</div>
</div>
</div>
<div class="form-group">
<label for="confirmPassword">Confirm Password</label>
<input
formControlName="confirmPassword"
type="text"
class="form-control"
id="confirmPassword"
placeholder="Confirm new Password">
<div
*ngIf="confirmPassword.touched && confirmPassword.invalid"
class="alert alert-danger">
<div *ngIf="confirmPassword.errors.required">Confirm password is required</div>
</div>
<div
*ngIf="confirmPassword.valid && form.invalid && form.errors?.confirmNewPassword"
class="alert alert-danger">
Passwords should match
</div>
</div>
<button type="submit" class="btn btn-primary">Change Password</button>
</form>
I'm try to make custom Validators that give user message when he/she leave a space on text but i received this error.
1-Cannot read property 'removeSpaceFromUserName' of undefined
2-Cannot read property 'required' of null
at Object.eval [as updateDirectives]
Here's the html of the component
<form [formGroup]='form'>
<div class="form-group">
<label for="username">Username</label>
<input
formControlName='username'
id="username"
type="text"
class="form-control">
<div *ngIf="username.touched && username.touched" class="alert alert-danger">
<div *ngIf="username.errors.required"> You need to enter user name</div>
<div *ngIf="username.errors.minlength"> Min Length is
{{ username.errors.minLength.requiredLength}}
</div>
<div *ngIf="UserNameValiditors.removeSpaceFromUserName">
removeSpaceFromUserName </div>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
formControlName='password'
id="password"
type="text"
class="form-control">
</div>
<button class="btn btn-primary" type="submit">Sign Up</button>
</form>
Here's the custom validator class
import { AbstractControl, ValidationErrors } from "#angular/forms";
export class UserNameValiditors {
static removeSpaceFromUserName(control: AbstractControl): ValidationErrors | null {
if ((control.value as string).indexOf(' ') >= 0) {
return {
removeSpaceFromUserName: true
};
}
else {
return null;
}
}
}
import { Component } from '#angular/core';
import { FormControl , FormGroup , Validators } from "#angular/forms";
import { UserNameValiditors } from './UserNameValditors';
#Component({
selector: 'signup-form',
templateUrl: './signup-form.component.html',
styleUrls: ['./signup-form.component.css']
})
export class SignupFormComponent {
form= new FormGroup(
{
username : new FormControl('',
[
Validators.required,
Validators.minLength(3) ,
UserNameValiditors.removeSpaceFromUserName
]) ,
password : new FormControl('',Validators.required)
});
get username()
{
return this.form.get('username');
}
}
You can try with this solution.
I have create a demo on Stackblitz
app.component.ts
myForms: FormGroup;
constructor(fb: FormBuilder) {
this.myForms = fb.group({
username: [null, Validators.compose([
Validators.required, Validators.minLength(3), usernameValidator])],
password: [null, [
Validators.required]]
});
}
app.component.html
<form [formGroup]="myForms">
<label>User Name :
<input type="text" formControlName="username">
</label><br>
<div class="errors" *ngIf="myForms.get('username').invalid && (myForms.get('username').touched || myForms.get('username').dirty)">
<div *ngIf="myForms.get('username').hasError('required')">
username is required
</div>
<div *ngIf="myForms.get('username').errors.minlength">
username must be at least 3 characters
</div>
<div class="error-text" *ngIf="myForms.get('username').hasError('removeSpaceFromUserName')">
removeSpaceFromUserName
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
formControlName='password'
id="password"
type="text"
class="form-control">
</div>
<button class="btn btn-primary" type="submit">Sign Up</button>
</form>
Use hasError() to check if certain error is present on the form.
html code
<div *ngIf="username.hasError('required')"> You need to enter user name</div>
<div *ngIf="username.hasError('minlength')"> Min Length is {{ username.hasError('minLength')}}
</div>f
<div *ngIf="username.hasError('removeSpaceFromUserName')">
removeSpaceFromUserName </div>
</div>
Your working code is here
If I tab through the text inputs without entering anything, the error msg divs display indicating that the required validator has fired correctly. However, if I type anything into one of the fields, the console immediately throws this error:
Cannot read property 'required' of null
Here is my component:
import { PasswordValidators } from './../validators/password.validators';
import { Component, OnInit } from '#angular/core';
import { FormBuilder, Validators, FormGroup, FormControl } from '#angular/forms';
#Component({
selector: 'app-changepassword-form',
templateUrl: './changepassword-form.component.html',
styleUrls: ['./changepassword-form.component.css']
})
export class ChangepasswordFormComponent {
form;
constructor(fb: FormBuilder) {
this.form = fb.group({
newPassword: ['', Validators.required],
confirmPassword: ['', Validators.required]
})
}
get newPassword() {
return this.form.get('newPassword');
}
get confirmPassword() {
return this.form.get('confirmPassword');
}
}
and HTML:
<form [formGroup]="form">
<div class="form-group">
<label for="newPassword">New Password</label>
<input formControlName="newPassword" id="newPassword" type="text" class="form-control">
<div class="alert alert-danger" *ngIf="newPassword.touched && newPassword.errors.required">
Required
</div>
</div>
<div class="form-group">
<label for="confirmPassword">Confirm Password</label>
<input formControlName="confirmPassword" id="confirmPassword" type="text" class="form-control">
<div class="alert alert-danger" *ngIf="confirmPassword.touched && confirmPassword.errors.required">
Required
</div>
</div>
<p><button class="btn btn-primary">Submit</button></p>
</form>
That error is coming from this:
*ngIf="newPassword.touched && newPassword.errors.required"
When you put in a value, there is no longer an errors collection so checking newPassword.errors.required generates that Cannot read property 'required' of null error.
Try something like this instead:
*ngIf="newPassword.touched && newPassword.errors?.required"
As an example, mine looks like this:
<div class="col-md-8">
<input class="form-control"
id="productNameId"
type="text"
placeholder="Name (required)"
required
minlength="3"
[(ngModel)] = product.productName
name="productName"
#productNameVar="ngModel" />
<span class="help-block" *ngIf="(productNameVar.touched ||
productNameVar.dirty || product.id !== 0) &&
productNameVar.errors">
<span *ngIf="productNameVar.errors.required">
Product name is required.
</span>
<span *ngIf="productNameVar.errors.minlength">
Product name must be at least three characters.
</span>
</span>
</div>
You can also use the following syntax and it will work without the need to have a value first:
form.get('newPassword').hasError('required')
This will check for 'required' in the errors.
This will work as well and it's more concise :
form.hasError('required','newPassword')
If you are compiling with AOT option, according to this article, you should privilege hasError() syntax:
Don’t use control.errors?.someError, use control.hasError(‘someError’)