My reactive form is not working at all, with all the validations failing. Any of the validations are not appearing on screen at all and the Save button when clicked is giving the following error in my devTools console:

user-register.component.html:8 ERROR TypeError: Cannot read properties of null (reading '_syncPendingControls')
    at syncPendingControls (forms.mjs:3352:8)
    at _FormGroupDirective.onSubmit (forms.mjs:5344:5)
    at FormGroupDirective_submit_HostBindingHandler (forms.mjs:5446:24)
    at executeListenerWithErrorHandling (core.mjs:24700:16)
    at wrapListenerIn_markDirtyAndPreventDefault (core.mjs:24733:22)
    at HTMLFormElement.<anonymous> (platform-browser.mjs:751:112)
    at _ZoneDelegate.invokeTask (zone.js:402:31)
    at core.mjs:14455:55
    at AsyncStackTaggingZoneSpec.onInvokeTask (core.mjs:14455:36)
    at _ZoneDelegate.invokeTask (zone.js:401:60)

I am unable to identify the error, please help.. I've checked everywhere, even made use of chatGPT and tried the responses, but in vain.

Below is my user-register.component.html code:

<div class="row">
  <div class="col-6 m-auto">
    <mat-card class="card m-auto">
      <mat-card-header class="card-header">
        <mat-card-title>Register</mat-card-title>
        <mat-card-subtitle>Register to unlock more features</mat-card-subtitle>
      </mat-card-header>
      <mat-card-content class="card-body">
        <form [formGroup]="registrationForm" (ngSubmit)="onSubmit()" #ngForm>
          <div class="form-group col-12">
              <label for="name" class="form-label">Name</label>
              <input type="text" class="form-control" formControlName="userName">
              <span *ngIf="!userName.valid && userName.touched" class="error-block">
                Please provide name!
              </span>
            </div>
  
          <div class="form-group col-12">
            <label for="email" class="form-label">Email</label>
            <input type="text" class="form-control" formControlName="email">
            <span *ngIf="!email.valid && email.touched" class="error-block">
              <span *ngIf="email.hasError('required')">
                Please provide email ID!
              </span>
              <span *ngIf="email.hasError('email')">
                Please provide a valid email ID!
              </span>
            </span>
          </div>
  
          <div class="form-group col-12">
            <label for="password" class="form-label">Password</label>
            <input type="password" class="form-control" formControlName="password">
            <span *ngIf="!password.valid && password.touched" class="error-block">
              <span *ngIf="password.hasError('minlength')">Please should not be less than 8 characters</span>
              <span *ngIf="password.hasError('required')">Please provide password</span>
            </span>
          </div>
  
          <div class="form-group col-12">
            <label for="cpassword" class="form-label">Confirm Password</label>
            <input type="password" class="form-control" formControlName="cpassword">
            <span *ngIf="!confirmPassword.valid && confirmPassword.touched" class="error-block">
              <span *ngIf="confirmPassword.hasError('minlength')">Please should not be less than 8 characters</span>
              <span *ngIf="confirmPassword.hasError('required')">Please provide password</span>
            </span>
          </div>
  
          <div class="form-group col-12">
            <label for="mobile" class="form-label">Mobile</label>
            <input type="text" class="form-control" formControlName="mobile">
            <span *ngIf="!mobile.valid && mobile.touched" class="error-block">
              <span *ngIf="mobile.hasError('minlength')">Please should not be less than 10 characters</span>
              <span *ngIf="mobile.hasError('required')">Please provide password</span>
            </span>
          </div>
  
          <br/>

          <div class="form-group col-12">
            <button type="submit" class="btn btn-primary">Save</button>
            <button type="reset" class="btn btn-secondary ml-2">Cancel</button>
          </div>
        </form>
      </mat-card-content>
    </mat-card>
  </div>
</div>

This is my user-register.component.ts file:

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

@Component({
  selector: 'app-user-register',
  templateUrl: './user-register.component.html',
  styleUrl: './user-register.component.css'
})
export class UserRegisterComponent implements OnInit {
  registrationForm: FormGroup;

  constructor() { }

  ngOnInit() {
      this.registrationForm = new FormGroup({
      userName: new FormControl('', Validators.required),
      email: new FormControl('', [Validators.required, Validators.email]),
      password: new FormControl('', [Validators.required, Validators.minLength(8)]),
      confirmPassword: new FormControl('', [Validators.required]),
      mobile: new FormControl('', [Validators.required, Validators.maxLength(10)])
    },
    {
      validators: this.passwordMatchingValidator,
    }
    )
  }

  passwordMatchingValidator(control: AbstractControl): {[key: string]: boolean} | null {
    return control.get('password')?.value === control.get('confirmPassword')?.value ? null : {mismatch: true};
  }

  get userName() {
    return this.registrationForm.get('userName') as FormControl;
  }

  get email() {
    return this.registrationForm.get('email') as FormControl;
  }

  get password() {
    return this.registrationForm.get('password') as FormControl;
  }

  get confirmPassword() {
    return this.registrationForm.get('confirmPassword') as FormControl;
  }

  get mobile() {
    return this.registrationForm.get('mobile') as FormControl;
  } 

  onSubmit() {
    console.log(this.registrationForm);
  }
}
1

There are 1 best solutions below

1
Naren Murali On

All I can see is that you have a typo on confirm password form field, you have given the name as cpassword instead of confirmPassword.

<div class="form-group col-12">
        <label for="confirmPassword" class="form-label">Confirm Password</label>
        <input type="password" class="form-control" formControlName="confirmPassword">
        <span *ngIf="!confirmPassword.valid && confirmPassword.touched" class="error-block">
          <span *ngIf="confirmPassword.hasError('minlength')">Please should not be less than 8 characters</span>
          <span *ngIf="confirmPassword.hasError('required')">Please provide password</span>
        </span>
      </div>

Both the model and view form control has to have the same name! But I never was able to replicate your issue, if its still not resolved, share back the stackblitz with the issue replicated!

import { bootstrapApplication } from '@angular/platform-browser';
import { Component, OnInit } from '@angular/core';
import {
  AbstractControl,
  FormControl,
  FormGroup,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms';

import 'zone.js';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { MatInputModule } from '@angular/material/input';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ReactiveFormsModule, CommonModule, MatCardModule, MatInputModule],
  template: `
    <div class="row">
  <div class="col-6 m-auto">
    <mat-card class="card m-auto">
      <mat-card-header class="card-header">
        <mat-card-title>Register</mat-card-title>
        <mat-card-subtitle>Register to unlock more features</mat-card-subtitle>
      </mat-card-header>
      <mat-card-content class="card-body">
        <form [formGroup]="registrationForm" (ngSubmit)="onSubmit()" #ngForm>
          <div class="form-group col-12">
              <label for="name" class="form-label">Name</label>
              <input type="text" class="form-control" formControlName="userName">
              <span *ngIf="!userName.valid && userName.touched" class="error-block">
                Please provide name!
              </span>
            </div>
  
          <div class="form-group col-12">
            <label for="email" class="form-label">Email</label>
            <input type="text" class="form-control" formControlName="email">
            <span *ngIf="!email.valid && email.touched" class="error-block">
              <span *ngIf="email.hasError('required')">
                Please provide email ID!
              </span>
              <span *ngIf="email.hasError('email')">
                Please provide a valid email ID!
              </span>
            </span>
          </div>
  
          <div class="form-group col-12">
            <label for="password" class="form-label">Password</label>
            <input type="password" class="form-control" formControlName="password">
            <span *ngIf="!password.valid && password.touched" class="error-block">
              <span *ngIf="password.hasError('minlength')">Please should not be less than 8 characters</span>
              <span *ngIf="password.hasError('required')">Please provide password</span>
            </span>
          </div>
  
          <div class="form-group col-12">
            <label for="confirmPassword" class="form-label">Confirm Password</label>
            <input type="password" class="form-control" formControlName="confirmPassword">
            <span *ngIf="!confirmPassword.valid && confirmPassword.touched" class="error-block">
              <span *ngIf="confirmPassword.hasError('minlength')">Please should not be less than 8 characters</span>
              <span *ngIf="confirmPassword.hasError('required')">Please provide password</span>
            </span>
          </div>
  
          <div class="form-group col-12">
            <label for="mobile" class="form-label">Mobile</label>
            <input type="text" class="form-control" formControlName="mobile">
            <span *ngIf="!mobile.valid && mobile.touched" class="error-block">
              <span *ngIf="mobile.hasError('minlength')">Please should not be less than 10 characters</span>
              <span *ngIf="mobile.hasError('required')">Please provide password</span>
            </span>
          </div>
  
          <br/>

          <div class="form-group col-12">
            <button type="submit" class="btn btn-primary">Save</button>
            <button type="reset" class="btn btn-secondary ml-2">Cancel</button>
          </div>
        </form>
      </mat-card-content>
    </mat-card>
  </div>
</div>
  `,
})
export class App {
  registrationForm!: FormGroup;

  constructor() {}

  ngOnInit() {
    this.registrationForm = new FormGroup(
      {
        userName: new FormControl('', Validators.required),
        email: new FormControl('', [Validators.required, Validators.email]),
        password: new FormControl('', [
          Validators.required,
          Validators.minLength(8),
        ]),
        confirmPassword: new FormControl('', [Validators.required]),
        mobile: new FormControl('', [
          Validators.required,
          Validators.maxLength(10),
        ]),
      },
      {
        validators: this.passwordMatchingValidator,
      }
    );
  }

  passwordMatchingValidator(
    control: AbstractControl
  ): { [key: string]: boolean } | null {
    return control.get('password')?.value ===
      control.get('confirmPassword')?.value
      ? null
      : { mismatch: true };
  }

  get userName() {
    return this.registrationForm.get('userName') as FormControl;
  }

  get email() {
    return this.registrationForm.get('email') as FormControl;
  }

  get password() {
    return this.registrationForm.get('password') as FormControl;
  }

  get confirmPassword() {
    return this.registrationForm.get('confirmPassword') as FormControl;
  }

  get mobile() {
    return this.registrationForm.get('mobile') as FormControl;
  }

  onSubmit() {
    console.log(this.registrationForm.valid);
  }
}

bootstrapApplication(App);

stackblitz