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
相关产品推荐
相关产品推荐

