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

Angular响应式表单注入NgForm报NullInjectorError问题咨询

问题描述

开发了通用错误展示组件ShowErrorComponent,构造函数注入NgForm后在模板驱动表单中可正常显示错误信息,但在响应式表单中使用时,表单无法渲染,抛出如下错误:

ERROR NullInjectorError: R3InjectorError(AppModule)[NgForm -> NgForm -> NgForm]: 
  NullInjectorError: No provider for NgForm!
    at NullInjector.get (core.mjs:6359:27)
    at R3Injector.get (core.mjs:6786:33)
    at R3Injector.get (core.mjs:6786:33)
    at R3Injector.get (core.mjs:6786:33)
    at ChainedInjector.get (core.mjs:13769:36)
    at lookupTokenUsingModuleInjector (core.mjs:3293:39)
    at getOrCreateInjectable (core.mjs:3338:12)
    at Module.ɵɵdirectiveInject (core.mjs:10871:12)
    at NodeInjectorFactory.ShowErrorComponent_Factory [as factory] (show-error.component.ts:9:32)
    at getNodeInjectable (core.mjs:3523:44)

已在模块中引入ReactiveFormsModule,相关代码如下:

组件代码

export class ShowErrorComponent {
  // path refering to the form-element
  @Input('path') controlPath = '';
  @Input('name') formName = '';

  constructor(private ngForm: NgForm) {}

  get errorMessages(): string[] | null {
    const form = this.ngForm.form;
    const control = form.get(this.controlPath);
    if (!control || !control.touched || !control.errors) {
      return null;
    }
    return this.getDisplayMessages(control.errors);
  }
  ....
}

响应式表单使用示例

<form
  novalidate
  class="register-form"
  (ngSubmit)="registerMember(registerForm.value)"
  [formGroup]="registerForm"
>
  <div formGroupName="personalInfo">
    <div class="form-group">
      <h3>Personal info:</h3>
      <div class="input-group mb-3">
        <label class="input-group-text" for="gender">Gender</label>
        <select class="form-select" id="membership" formControlName="gender">
          <option value="diverse">Diverse</option>
          <option value="male">Male</option>
          <option value="female">Female</option>
        </select>
      </div>
      <app-show-error name="Gender" path="personalInfo.gender"></app-show-error>
      ...
   </div>
    ...
 </div>
</div>

响应式表单初始化代码

constructor(fb: FormBuilder) {
    this.registerForm = fb.group({
      personalInfo: fb.group({
        gender: ['diverse'],
        firstname: ['', [Validators.required]],
        lastname: ['', [Validators.required]],
        birthdate: [new Date(), [Validators.required]]
      }),
      ...
    })
报错原因

NgForm是Angular模板驱动表单的专属服务,只有当表单采用模板驱动方式(不绑定[formGroup],依赖Angular自动创建的NgForm实例)时,Angular才会在注入器中提供NgForm的提供者。

而响应式表单通过[formGroup]绑定自定义FormGroup实例时,Angular不会创建NgForm对象,此时组件构造函数注入NgForm就会因找不到对应提供者抛出NullInjectorError。

解决方案

要让组件同时兼容两种表单类型,需替换NgForm注入,改为注入ControlContainer接口——NgForm和响应式表单的FormGroupDirective都实现了该接口,可统一获取表单容器实例。

修改后的组件代码如下:

import { ControlContainer, FormGroup } from '@angular/forms';

export class ShowErrorComponent {
  @Input('path') controlPath = '';
  @Input('name') formName = '';

  constructor(private controlContainer: ControlContainer) {}

  get errorMessages(): string[] | null {
    const form = this.controlContainer.control as FormGroup;
    const control = form.get(this.controlPath);
    if (!control || !control.touched || !control.errors) {
      return null;
    }
    return this.getDisplayMessages(control.errors);
  }
  
  // 保留原错误信息转换逻辑
  private getDisplayMessages(errors: any): string[] {
    const messages: string[] = [];
    if (errors.required) {
      messages.push(`${this.formName} 是必填项`);
    }
    // 其他错误类型处理逻辑
    return messages;
  }
}

修改后组件既能在模板驱动表单中正常工作,也能在响应式表单中获取对应FormGroup实例,不会再出现提供者缺失的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 05:40:22