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

使用@ngx-formly v5整合自定义Radio组件遇值访问器错误

问题:自定义Radio组件结合@ngx-formly v5时的表单关联错误

自定义Radio组件常规用法

<custom-radio
  name="regular"
  value="1"
  label="Regular"
>
</custom-radio>

渲染后的简化HTML:

<custom-radio>
  <label>
    <input type="radio">
    <span class="faux-radio">
      Regular
    </span>
  </label>
</custom-radio>

Formly配置

Formly模块

FormlyModule.forRoot({
   types: [
    {
      name: "custom-radio",
      component: FormlyCustomRadio, // 自定义的Formly包装组件
    }
   ],
}),

包装组件代码

@Component({
  selector: 'formly-custom-radio',
  template: `
     <custom-radio
        *ngFor="let option of to.options"
        [formControl]="formControl"
        [formlyAttributes]="field"
        [name]="to.name"
        [value]="option.key"
        [label]="option.label"
   >
   </custom-radio>
   `
})
export class FormlyCustomRadio extends FieldType<FieldTypeConfig> {}

Formly字段配置

const fields: FormlyFieldConfig[] = [
    {
      key: "dog",
      type: "custom-radio",
      templateOptions: {
        label: "你养狗狗了吗?",
        name: "dog",
        options: [
          { key: "1", label: "是" },
          { key: "2", label: "否" },
        ],
      },
    },
]

报错信息

Error: No value accessor for form control with unspecified name attribute

解决方案

报错核心是自定义custom-radio组件未实现Angular的ControlValueAccessor接口,导致表单无法识别其作为控件的价值访问逻辑。以下是两种无需重写原组件样式/逻辑的方案:

方案1:用指令实现ControlValueAccessor(推荐)

创建一个指令,在不修改原组件的前提下,为custom-radio添加表单交互能力:

import { Directive, HostListener, ElementRef, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Directive({
  selector: 'custom-radio',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomRadioValueAccessor),
      multi: true
    }
  ]
})
export class CustomRadioValueAccessor implements ControlValueAccessor {
  private onChange: (value: any) => void = () => {};
  private onTouched: () => void = () => {};

  constructor(private el: ElementRef) {}

  private get nativeRadio(): HTMLInputElement {
    return this.el.nativeElement.querySelector('input[type="radio"]');
  }

  @HostListener('change', ['$event.target.checked'])
  onRadioChange(checked: boolean) {
    if (checked) {
      this.onChange(this.nativeRadio.value);
    }
    this.onTouched();
  }

  writeValue(value: any): void {
    if (this.nativeRadio) {
      this.nativeRadio.checked = this.nativeRadio.value === value;
    }
  }

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

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

  setDisabledState(isDisabled: boolean): void {
    if (this.nativeRadio) {
      this.nativeRadio.disabled = isDisabled;
    }
  }
}

在模块中声明该指令后,custom-radio即可被Angular表单正常识别。

方案2:手动同步Formly包装组件的表单状态

修改包装组件的模板和逻辑,手动同步单选框状态与表单控件:

@Component({
  selector: 'formly-custom-radio',
  template: `
     <custom-radio
        *ngFor="let option of to.options"
        [name]="to.name"
        [value]="option.key"
        [label]="option.label"
        (change)="onRadioChange(option.key)"
        [checked]="formControl.value === option.key"
   >
   </custom-radio>
   `
})
export class FormlyCustomRadio extends FieldType<FieldTypeConfig> {
  onRadioChange(value: any) {
    this.formControl.setValue(value);
    this.formControl.markAsTouched();
  }
}

若原custom-radio未暴露change事件和checked属性,可通过ElementRef获取内部原生radio的状态进行同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 10:45:34