错误:在开关上未指定名称属性的表单控件没有值访问器。

238

这是我的Angular组件:

@Component( {
    selector: 'input-extra-field',
    template: `
            <div class="form-group" [formGroup]="formGroup" >
                <switch [attr.title]="field.etiquette" 
                    [attr.value]="field.valeur" [(ngModel)]="field.valeur"
                    [formControl]="fieldControl" [attr.id]="name" [attr.disabled]="disabled">
                </switch>
                <error-messages [control]="name"></error-messages>
            </div>
    `
} )

这是我的课程:

export class SwitchExtraField extends ExtraField {
    @Input() field: ExtraFormField;
    @Input() entity: { fields: Object };
    @Input() formGroup: FormGroup;

    constructor( formDir: NgForm ) {
        super( null, null, formDir );
    }

    get disabled(): string {
        if ( this.field && !!this.field.saisissable && !this.field.saisissable )     {
            return 'disabled';
        }
        return null;
    }
}

编译时出现了以下错误:

ERROR Error: No value accessor for form control with unspecified name attribute
  at _throwError (forms.es5.js:1918)
  at setUpControl (forms.es5.js:1828)
  at FormControlDirective.webpackJsonp.../../../forms/@angular/forms.es5.js.FormControlDirective.ngOnChanges (forms.es5.js:4617)

当我将元素切换为输入时,它可以工作。需要知道的是,我在使用相同结构的其他组件时它可以正常工作。


2
在这里阅读关于 ControlValueAccessor 的内容 - 在 Angular 表单中实现 ControlValueAccessor 时永远不再感到困惑 - Max Koretskyi
这可能会对你有所帮助:https://dev59.com/bFYN5IYBdhLWcg3w5r2Y - Dinistro
3
@MaxKoretskyi的“再也不会在实现Angular表单中的ControlValueAccessor时感到困惑”链接已更新。 - mcalex
我之所以出现这个错误,是因为我有一个自定义组件,其中有一个名为formControl@Input属性,用法略有不同。我现在感觉有点傻。 - O-9
31个回答

316

我通过为负责 [(ngModel)] 属性的元素添加 name="fieldName" ngDefaultControl 属性来修复此错误。


53
需要进一步解释才能使这个答案更好。例如,你在哪里找到ngDefaultControl的文档? - isherwood
48
我认为 name="fieldname" 不是必需的,但是 ngDefaultControl 可以解决这个问题。 - michaeak
13
这里有更多的解释。https://dev59.com/m1YO5IYBdhLWcg3wDNMa#46465959ngDefaultControl 是 Angular 表单控件中的一个指令,用于为表单控件提供默认值。它通常用于响应式表单中的 FormControlFormGroupFormArray 控件。如果表单控件没有绑定任何数据,那么 ngDefaultControl 指令就会提供一个默认的值。 - I'm nidhin
7
我通过导入表单组中使用的元素的模块包(例如AngularEditorModule)来修复了这个问题,以便模板可以识别控件并且ngDefaultControl可以访问它。我是在进行单元测试时发现这个问题的。 - aj go
1
只需添加ngDefaultControl,这个错误就被解决了。 - Chris Snowden
显示剩余4条评论

244

我曾经遇到同样的问题,问题出在我的子组件里有一个名为formControl@input

所以我只需要做如下修改即可:

<my-component [formControl]="formControl"><my-component/>

目标:

<my-component [control]="control"><my-component/>

ts:

@Input()
control:FormControl;

3
在先前的评论中提到,它适用于Angular 10。跟踪这个问题真的很难,但之后,“formControl”不应该被用作组件@Input属性名称是有道理的,因为可能会存在命名空间冲突。另一个命名解决方案是将由FormControl实例提供的字段重命名为_formControl。 - Thomas
这对我来说是正确的解决方案,谢谢。 - André Machado
非常感谢。这个问题真是让人烦恼,但这个修复方法完美解决了。 - vikingsteve

82

我在编写 Angular 7 中的自定义表单控件组件时也遇到了这个错误。但是,所有答案都不适用于 Angular 7。

在我的情况下,以下内容需要添加到 @Component 装饰器中:

  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => MyCustomComponent),  // replace name as appropriate
      multi: true
    }
  ]

这是一个“我不知道它为什么有效,但它确实有效”的案例。将其归咎于Angular方面的设计/实现不良。


15
这段代码告诉Angular的依赖注入层,当其他类(例如formControlName指令)要求使用标记NG_VALUE_ACCESSOR时,应返回您的类。如果没有这个代码,Angular就无法知道您的类是自定义表单控件(在编译过程中接口等所有信息都被剥离了)。 - Max Mumford

44

我也遇到了同样的错误,Angular 7

 <button (click)="Addcity(city.name)" [(ngModel)]="city.name"  class="dropdown-item fontstyle"
     *ngFor="let city of Cities; let i = index">
      {{city.name}}
 </button>

我刚刚添加了ngDefaultControl

   <button (click)="Addcity(city.name)" [(ngModel)]="city.name"  ngDefaultControl class="dropdown-item fontstyle"
 *ngFor="let city of Cities; let i = index">
  {{city.name}}


33

在运行卡尔玛单元测试用例时,我遇到了这个错误。将MatSelectModule添加到导入中可以解决此问题。

imports: [
        HttpClientTestingModule,
        FormsModule,
        MatTableModule,
        MatSelectModule,
        NoopAnimationsModule
      ],

2
只有安装了“Angular Material”,否则您不需要这个。 - Mikefox2k
2
我想补充一下,这适用于 Angular Material 中的任何“输入”元素。例如,我有一个带有表单控件的滑动开关元素,在运行 Karma 测试时出现了“无值访问器”错误。结果,我不得不在我的“spec.ts”类中添加 MatSlideToggleModule 导入,以便它识别该输入。 - Gabriel Lovetro
我的问题与此非常相似,但与另一个第三方模块(UiSwitchModule)有关。 - Ben Thomson
相同的问题但不同的模块。我必须添加 MatAutocompleteModuleMatInputModule - nedstark179

19

我在使用Jasmine进行单元测试时遇到了这个错误信息。我给自定义元素(在我这里是一个Angular Material幻灯片切换)添加了ngDefaultControl属性,这解决了错误。

<mat-slide-toggle formControlName="extraCheese">
  Extra Cheese
</mat-slide-toggle>
将上面的元素改为包含ngDefaultControl属性。
<mat-slide-toggle ngDefaultControl formControlName="extraCheese">
 Extra Cheese
</mat-slide-toggle>

这对我很有帮助,我的应用程序运行缓慢并显示错误,将其添加到我的导航栏中解决了问题。 - MADMVX
这对我有用。在我的情况下,我在Angular模板中的formControl元素内部有一个子表单formGroup。将ngDefaultControl添加到顶级表单中解决了问题。 - RedRain

16

当您在一个不能拥有值的元素上使用 ngModel 或 formControl 时,就会出现此问题,例如 <div> 元素。

如果像这样使用 ngModel 或 formControl,就会出现问题:

<div [(ngModel)]="myModel"> <--- wrong place
    <input type="text" />
</div>

解决方案:

<div>
    <input type="text" [(ngModel)]="myModel" /> <--- correct place
</div>

来源:https://github.com/angular/angular/issues/43821#issuecomment-992305494

这个问题是由于 Angular 的 AOT 编译器在解析模板时出现了错误。当你使用管道的名称作为模板变量时,AOT 编译器会将其视为管道的实例而不是模板变量。要解决此问题,你需要将模板变量重命名为不同的名称,以避免与管道名称冲突。

1
在我的情况下,我将ngModel放置在select的'option'标签中,而不是'select'标签中。 - Amir Aghajani

15

在我的情况下,我忘记将providers: [INPUT_VALUE_ACCESSOR]添加到我的自定义组件中。

我创建了一个名为 INPUT_VALUE_ACCESSOR 的输入值提供者:

export const INPUT_VALUE_ACCESSOR = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => TextEditorComponent),
  multi: true,
};

这是我的情况,看起来这个错误是由多个问题引起的。 - undefined

15

当我把我的组件输入命名为'formControl'时,我也收到了这个错误。可能它已经被保留用于其他用途。如果你想在组件之间传递FormControl对象,请像这样使用:

我也因为给我的组件输入命名为'formControl'而遇到了这个错误。可能这个名称已经被保留用于其他用途。如果你想在组件之间传递FormControl对象,请按照以下方式使用:

@Input() control: FormControl;

不要这样:

@Input() formControl: FormControl;

有点奇怪,但是有效 :)


这是因为formControl是Angular绑定表单控件到输入字段的默认指令。 - sschmid

10

我的问题是我创建了一个使用保留名称formControl@Input变量。


非常感谢!我也遇到了这个问题。 - tmsbrndz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接