You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular注册表单自定义验证失效及FormGroup实例错误求助

解决Angular注册表单的两个错误

错误原因及修复方案

错误1: ERROR TypeError: Cannot read properties of undefined (reading 'registerForm')

问题出在自定义验证器confirmationPass上:

  • 直接传入this.confirmationPass作为验证器时,方法内部的this不指向组件实例,导致this.registerForm为undefined
  • 表单初始化过程中,passwordConfirmaton控件创建时,registerForm还未完全初始化,直接访问会报错

修复方式:

  1. 用bind(this)绑定验证器的上下文,确保this指向组件实例
  2. 自定义验证器接收FormControl参数,通过控件的parent属性获取表单实例,避免直接依赖组件的registerForm

错误2: ERROR Error: NG01052: formGroup expects a FormGroup instance

原因是组件类中registerForm仅声明但未在模板渲染前初始化,模板加载时registerForm仍为undefined,Angular无法找到有效的FormGroup实例。

修复方式:

  • 在组件类中直接初始化空的FormGroup,避免模板加载时出现undefined
  • 或者在模板的form标签上添加*ngIf="registerForm",确保表单仅在registerForm存在时渲染

修正后的代码

registration.component.ts

import { Component, ContentChild, OnInit } from '@angular/core';
import { ReactiveFormsModule, FormControl, FormGroup, Validators, AbstractControl } from '@angular/forms';
import { faEye, faEyeSlash, faArrowRightToBracket, faCloudUpload } from '@fortawesome/free-solid-svg-icons';

@Component({
  selector: 'app-registration',
  templateUrl: './registration.component.html',
  styleUrls: ['./registration.component.css']
})
export class RegistrationComponent implements OnInit{
  // 提前初始化空FormGroup,避免模板加载时undefined
  registerForm: FormGroup = new FormGroup({});
  showPassword : boolean = false;
  showPasswordCon: boolean = false;
  iconof = faEye;
  iconshow = faEyeSlash;
  iconlogin = faArrowRightToBracket;
  iconUpload = faCloudUpload;
  @ContentChild("inInput") input: any;

  constructor(){}
  ngOnInit(): void {
    this.registerForm = new FormGroup({
      fullName: new FormControl(null, Validators.required),
      // 修正正则:原正则仅匹配单个字符,改为匹配多个字符
      userName: new FormControl(null, [Validators.required, Validators.pattern('^[a-z0-9_-]+$')]),
      email: new FormControl(null, [Validators.required, Validators.email]),
      phoneNumber: new FormControl(null, [Validators.required]),
      // 转义正则中的反斜杠,确保正则生效
      password: new FormControl(null, [Validators.required, Validators.minLength(8), Validators.maxLength(15), Validators.pattern('(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,}')]),
      // 绑定验证器的this上下文
      passwordConfirmaton: new FormControl(null, [Validators.required, Validators.minLength(8), Validators.maxLength(15), this.confirmationPass.bind(this)]),
      dateOfBirth: new FormControl(null),
      addres: new FormControl(null),
      userImage: new FormControl(null)
    })
  }

  onSubmite(){
    console.log(this.registerForm);
  }

  toggleShow() {
    this.showPassword = !this.showPassword;
  }

  toggleShowCon() {
    this.showPasswordCon = !this.showPasswordCon;
  }

  // 修正验证器逻辑:通过control.parent获取表单实例
  confirmationPass(control: AbstractControl): {[key: string]: boolean} | null {
    if (!control.parent) return null;
    
    const pass = control.parent.get('password')?.value;
    const passCon = control.value;
    
    return pass !== passCon ? { passwordMismatch: true } : null;
  }
}

registration.component.html

<section class="ftco-section">
    <div class="container">
  <div class="row justify-content-start">
    <div class="col-md-6 text-start me-5">
                <img class="heading-section " src="../assets/imgs/userlogo.png" alt="logo"><i><h3 class=" text-center">Register Form</h3></i>
            </div>
<div class="row justify-content-start pe-5">
  <div class="col-md-6 col-lg-6">
    <div class="login-wrap p-0">
     <!-- 添加*ngIf确保表单存在时渲染 -->
     <form *ngIf="registerForm" [formGroup]="registerForm" (ngSubmit)="onSubmite()" action="#" class="signin-form">
      <div class="form-group">
       <label>*Full name:</label>
        <input formControlName="fullName" id="Fullname-field" type="text" class="form-control" placeholder="FullName" required>
      </div>
      <div class="form-group">
        <label>*User Name:</label>
        <input formControlName="userName" id="Username-field" type="text" class="form-control" placeholder="Unique Username" required>
      </div>
      <div class="form-group">
        <label>*Email:</label>
        <input formControlName="email" id="email-field" type="email" class="form-control" placeholder="youremail@exampil.com" required>
      </div>
      <div class="form-group">
        <label>*Phone Number:</label>
        <input formControlName="phoneNumber" id="phoneNumber" type="tel" class="form-control" placeholder="+96653*******" required>
      </div>
      <div class="form-group">
        <label>*Password:</label>
        <input formControlName="password" id="password-field" [type]="showPassword? 'text' : 'password'" class="form-control" placeholder="Password" required>
        <span class="field-icon" ><a class="type-toggle" (click)="toggleShow()">
          <fa-icon class="show-option" style=" color:#4c9781;"  [hidden]="!showPassword" [icon]="iconof"></fa-icon>
          <fa-icon class="hide-option" style=" color:#4c9781;" [hidden]="showPassword" [icon]="iconshow"></fa-icon>
       </a></span>
      </div>
      <div class="form-group">
        <label>*Password Confirmation:</label>
        <input formControlName="passwordConfirmaton" id="passwordConf-field" [type]="showPasswordCon? 'text' : 'password'" class="form-control" placeholder="Password Confirmation" required>
        <span class="field-icon" ><a class="type-toggle" (click)="toggleShowCon()">
          <fa-icon class="show-option" style=" color:#4c9781;"  [hidden]="!showPasswordCon" [icon]="iconof"></fa-icon>
          <fa-icon class="hide-option" style=" color:#4c9781;" [hidden]="showPasswordCon" [icon]="iconshow"></fa-icon>
       </a></span>
      </div>
      <div class="form-group">
        <label>*Birthday Date:</label>
        <input formControlName="dateOfBirth" id="DOB" type="date" class="form-control" placeholder="Enter Your Birthday Date" >
      </div>
      <div class="form-group">
        <label>Adress:</label>
        <input formControlName="addres" id="adress" type="text" class="form-control" placeholder="Enter Your Addres" >
      </div>
      <div class="form-group">
        <label for="file-upload" class="custom-file-upload">
          <fa-icon [icon]="iconUpload" class="fa-lg"></fa-icon> upload User Image
      </label>
      <!-- 添加formControlName绑定,让表单获取文件值 -->
      <input id="file-upload" type="file" formControlName="userImage"/>
      </div>

      <div class="form-group">
        <button type="submit" class="link form-control btn btn-primary submit px-3">Sign Up</button>
      </div>
      <div class="form-group d-md-flex">
        <div class=" text-md-right">
          <span class="link justify-content-center"><a routerLink="/login" style="color: #609696">Log in Here <fa-icon [icon]="iconlogin"></fa-icon></a></span>
        </div>
      </div>
    </form>
    </div>
  </div>
  </div>
    </div>
    </div>
</section>

额外说明

  1. 修正用户名正则:原正则仅匹配单个字符,改为^[a-z0-9_-]+$支持多字符用户名
  2. 转义密码正则中的反斜杠,确保正则规则能正确解析
  3. 文件上传控件添加formControlName="userImage",让表单能捕获文件输入值
  4. 自定义验证器返回的错误key改为passwordMismatch,语义更清晰

内容的提问来源于stack exchange,提问作者Roaa Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 15:39:55