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

Reactive Forms结合ControlValueAccessor自定义控件赋值未生效问题

问题根因

你遇到的问题是由两处核心配置和实现缺失导致的:

  • 第一,自定义表单控件TextboxComponent没有注册NG_VALUE_ACCESSOR提供者,Angular表单无法识别该组件为合法的表单控件,因此不会主动调用writeValue方法同步表单值到控件内部,这就是你表单已经赋值,但输入框没有显示的直接原因。
  • 第二,TextboxComponent内部的ControlValueAccessor实现不完整:
    • 你当前给onChange、onTouch写的是TypeScript类型声明,没有赋初始空函数,后续调用会抛出undefined错误
    • 值变更的setter中没有调用onChange回调,输入框内容变更时无法同步回上层表单
    • writeValue没有做空值兼容,表单赋null/undefined时会有异常

修复后的TextboxComponent代码

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

@Component({
  selector: 'app-textbox',
  template:
  `
    <input [(ngModel)]="value" [disabled]="disabled" />
  `,
  styleUrls: ['./textbox.component.css'],
  // 新增:注册NG_VALUE_ACCESSOR,告诉Angular这是合法的表单控件
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => TextboxComponent),
      multi: true
    }
  ]
})
export class TextboxComponent implements OnInit, ControlValueAccessor {

  constructor() { }
  writeValue(obj: any): void {
    // 新增空值兼容
    this._value = obj ?? '';
  }
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouch = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  disabled = false;

  // 修正:赋初始空函数,不是只声明类型
  onChange = (val: string) => {}
  onTouch = () => {};

  private _value:string = '';
  public get value():string {
    return this._value
  } 
  public set value(value:string){
    this._value = value;
    // 新增:值变更时通知上层表单
    this.onChange(value);
    this.onTouch();
  }

  ngOnInit(): void {
  }
}

补充说明

修复后重新运行,表单赋值的test就会正常显示在输入框中,同时你在输入框中修改内容也会同步回上层FormGroup的对应控件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 12:18:01