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

Angular 14自定义FormGroup组件无法渲染问题求助

问题分析与修复:自定义FormGroup组件无法渲染

核心错误点

  • formGroupName使用错误:实现ControlValueAccessor的自定义组件是值访问器,需用formControlName绑定父表单的FormGroup控件,而非formGroupName(后者用于标记表单组层级容器,不能直接绑定值访问器组件)。
  • ControlValueAccessor实现不完整:
    • 子组件未正确触发onTouched事件,父表单无法感知组件触摸状态;
    • valueChanges订阅未销毁,存在内存泄漏风险;
    • text-input组件的ngModel绑定引发循环更新问题。

修复步骤

1. 修正父组件中viewbox-input的绑定方式

将父组件内的代码:

<viewbox-input formGroupName="viewBox"></viewbox-input>

替换为:

<viewbox-input formControlName="viewBox"></viewbox-input>

2. 完善ViewboxInputComponent的ControlValueAccessor实现

更新viewbox-input.component.ts:

import { Component, OnDestroy } from '@angular/core';
import { FormGroup, FormControl, ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject, takeUntil } from 'rxjs';

@Component({
  selector: "viewbox-input",
  templateUrl: "./viewbox-input.component.html",
  styleUrls: ["./viewbox-input.component.css"],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: ViewboxInputComponent,
      multi: true
    }
  ]
})
export class ViewboxInputComponent implements ControlValueAccessor, OnDestroy{
  private destroy$ = new Subject<void>();
  ViewboxForm : FormGroup = new FormGroup({
    x: new FormControl(''),
    y: new FormControl(''),
    width: new FormControl(''),
    height: new FormControl('')
  });

  onChange: any = () => {};
  onTouched: any = () => {};

  writeValue(value: any){
    if(value){ this.ViewboxForm.setValue(value); }
  }

  registerOnChange(fn: any){ 
    this.ViewboxForm.valueChanges
      .pipe(takeUntil(this.destroy$))
      .subscribe(fn); 
  }

  registerOnTouched(fn: any){ 
    this.onTouched = fn; 
  }

  onInputBlur(){
    this.onTouched();
  }

  ngOnDestroy(){
    this.destroy$.next();
    this.destroy$.complete();
  }
}

3. 更新viewbox-input模板,添加触摸事件绑定

修改viewbox-input.component.html:

<section class="shell" [formGroup]="ViewboxForm">
  <p>ViewBox</p>
  <text-input formControlName="x" [label]="'x'" (blur)="onInputBlur()"></text-input>
  <text-input formControlName="y" [label]="'y'" (blur)="onInputBlur()"></text-input>
  <text-input formControlName="width" [label]="'width'" (blur)="onInputBlur()"></text-input>
  <text-input formControlName="height" [label]="'height'" (blur)="onInputBlur()"></text-input>
</section>

4. 修复TextInputComponent的循环更新问题

更新text-input.component.ts:

import { Component, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: "text-input",
  templateUrl: "./text-input.component.html",
  styleUrls: ["./text-input.component.css"],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting : TextInputComponent,
      multi: true
    }
  ]
})
export class TextInputComponent implements ControlValueAccessor{

  @Input() label!: string;
  
  field  = '';

  onChange : any = () =>{};
  onTouch : any = () => {};

  writeValue(value: any){ 
    if(value !== undefined){
      this.field = value;
    }
  }

  registerOnChange(fn: any){ this.onChange = fn; }

  registerOnTouched(fn: any){ this.onTouch = fn; }

  onInputChange(event: Event){
    const value = (event.target as HTMLInputElement).value;
    this.field = value;
    this.onChange(value);
  }

  onInputBlur(){
    this.onTouch();
  }
}

更新text-input.component.html:

<label>
  <span>{{label}}</span>
  <input type="text" [value]="field" (input)="onInputChange($event)" (blur)="onInputBlur()" />
</label>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 05:03:27