是什么导致“control.registerOnChange不是函数”错误

时间:2017-01-04 22:05:21

标签: forms angular

我有一个使用反应形式方法的表格。表单在我的哈巴狗中创建如下:

form([formGroup]='form', novalidate='', (ngSubmit)='postSurvey(form.value, form.valid)')

除非我尝试在javascript部分中更改表单(FormArray),否则一切正常。我收到以下错误:

EXCEPTION: Error in http://localhost:8080/app/components/fillForm.template.html:0:326 caused by: control.registerOnChange is not a function
core.umd.js:3497 TypeError: control.registerOnChange is not a function
    at setUpControl (http://localhost:8080/node_modules/@angular/forms/bundles/forms.umd.js:1634:17)
    at eval (http://localhost:8080/node_modules/@angular/forms/bundles/forms.umd.js:4752:25)
    at Array.forEach (native)
    at FormGroupDirective._updateDomValue (http://localhost:8080/node_modules/@angular/forms/bundles/forms.umd.js:4747:29)
    at FormGroupDirective.ngOnChanges (http://localhost:8080/node_modules/@angular/forms/bundles/forms.umd.js:4616:22)
    at Wrapper_FormGroupDirective.ngDoCheck (/ReactiveFormsModule/FormGroupDirective/wrapper.ngfactory.js:30:18)
    at View_FillFormComponent2.detectChangesInternal (/AppModule/FillFormComponent/component.ngfactory.js:275:32)
    at View_FillFormComponent2.AppView.detectChanges (http://localhost:8080/node_modules/@angular/core/bundles/core.umd.js:12592:18)
    at View_FillFormComponent2.DebugAppView.detectChanges (http://localhost:8080/node_modules/@angular/core/bundles/core.umd.js:12739:48)
    at ViewContainer.detectChangesInNestedViews (http://localhost:8080/node_modules/@angular/core/bundles/core.umd.js:12850:41)
    at CompiledTemplate.proxyViewClass.View_FillFormComponent0.detectChangesInternal (/AppModule/FillFormComponent/component.ngfactory.js:64:14)
    at CompiledTemplate.proxyViewClass.AppView.detectChanges (http://localhost:8080/node_modules/@angular/core/bundles/core.umd.js:12592:18)
    at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (http://localhost:8080/node_modules/@angular/core/bundles/core.umd.js:12739:48)
    at CompiledTemplate.proxyViewClass.AppView.internalDetectChanges (http://localhost:8080/node_modules/@angular/core/bundles/core.umd.js:12577:22)
    at CompiledTemplate.proxyViewClass.View_FillFormComponent_Host0.detectChangesInternal (/AppModule/FillFormComponent/host.ngfactory.js:29:19)

我更改表单的代码非常复杂,我无法简化它或在plunker中重现它。不仅仅是直接找到解决方案(由于细节太少而太难),我想了解这个错误意味着什么?什么可能导致这个错误。

我已经发现错误发生在我的HTML中的[formGroup]='form'

任何建议都会有所帮助。

更新我在angular github here上提交了一个问题,并提出了修复here重现问题的关键词是here

14 个答案:

答案 0 :(得分:26)

是的,该错误消息有点神秘,但是如果您使用 FormBuilder ,当您在组件中向 FormGroup 添加控件并将其命名为时,您会看到此信息“A”,但是忘记将 formControlName =“A”的输入添加到模板中,或 formControlName 表示预期的输入不是 A ,或为空,或不存在。

基本上,它说:“我无法将FormGroup中的控件与模板中的控件匹配”。

答案 1 :(得分:21)

在我的情况下,抛出此错误是因为我使用FormControlName而不是FormArrayName绑定到模板中的FormArray

我的组件代码:

public form = new FormGroup({
   ...
   checkboxes: new FormArray([....])
})

抛出错误的模板代码:

<input type="checkbox" formControlName="checkboxes" />

修复:

<input type="checkbox" formArrayName="checkboxes" />

答案 2 :(得分:19)

我遇到了寻找类似问题的解决方案,然后自己找到了解决方案。 我的问题如下。我有一个这样的表格

form: FormGroup = new FormGroup({
  status: new FormArray([])
});

最初,它由模板上每个状态的复选框列表表示。然后我创建了一个自定义组件来表示status选择器,并在模板中使用它,如此

<status-selector [formControlName]="'status'"></status-selector>

问题是formControlName必须指向FormControl实例,但实际上它指向FormArray实例。因此,更改为status: new FormControl([])可以解决此问题。

答案 3 :(得分:7)

在我的情况下,当formControl名称与页面上的模板变量相同时发生错误。例如

<select id="status" [formControl]="userStatus">...</select>

<form-status #userStatus ></form-status> //matching template variable name

答案 4 :(得分:4)

当混合模板驱动与反应驱动方法(错误)混合时,我也遇到了此错误:

<input #inputCtrl
       [formControl]="inputCtrl"
/>

inputCtrl已在组件中正确定义。当然,#inputCtrl必须报废才能正常工作(很难看到输入何时具有约10个属性)。

答案 5 :(得分:2)

this.extensionForm = this._fb.group({
      id: [''],
      category: [12],
      extensions: new FormArray([]),
      priority: ['', []],
    });
    formArray.push(this.extensionForm);
<块引用>

注意:- 错误是因为您使用了 formControlName 在你声明 formArray 的地方,你必须使用 formArrayName 来代替

<input type="text" formControlName="extensions" />

simple solution: 

<input type="checkbox" formArrayName="extensions" />

答案 6 :(得分:1)

也许您已将控件元素移到模板中的组外。

行:

<div formGroupName="passwordForm">
     Password: <input type="password" formControlName="password">
     Confirm: <input type="password" formControlName="confirmPassword">
</div>

不行:

Password: <input type="password" formControlName="password">
<div formGroupName="passwordForm">
     Confirm: <input type="password" formControlName="confirmPassword">
</div>

答案 7 :(得分:1)

对于未来的读者,我的问题很简单,它会导致 TypeError: control.registerOnChange is not a function

当我创建新的 FormGroup 时,我不小心使用了 FormGroup 而不是 FormControl

  myForm: FormGroup = new FormGroup({
    lname: new FormGroup({}),
    fnam: new FormGroup({}),
    date: new FormGroup({}),
  });

应该是这样的:

  myForm: FormGroup = new FormGroup({
    lname: new FormControl(''),
    fnam: new FormControl(''),
    date: new FormControl(null),
  });

希望这会在未来为某人节省几分钟!

答案 8 :(得分:1)

在 Angular 中,当我尝试构建自己的表单组件并忘记实现 ControlValueAccessor 接口时遇到了同样的问题:

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

@Component({
  selector: 'my-country-select',
  templateUrl: './country-select.component.html',
  styleUrls: ['./country-select.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CountrySelectComponent),
      multi: true,
    },
  ],
})
export class CountrySelectComponent implements OnInit, OnChanges, ControlValueAccessor {

  propagateChange = (_: any) => { }; // ControlValueAccessor 

  private internalValue: string | undefined;

  get value(): string | undefined {
    return this.internalValue;
  }
  set value(value: string | undefined) {
    this.internalValue = value;
    this.propagateChange(value);
  }

  // some other methods here

  // implementing the ControlValueAccessor interface with these three methods
  writeValue(obj: any): void {
    if (obj) {
      this.value = obj;
    }
  }

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

  registerOnTouched(fn: any): void {
    // throw new Error('Method not implemented.');
  }
}

答案 9 :(得分:0)

当我们在ng-template中与*ngIf一起使用反应形式时,也会出现此错误。

为避免这种情况,请使用ng-container,不要使用ngElse

答案 10 :(得分:0)

添加造成我情况的原因。

.ts文件,

...

export class MyComponent {
  dateFrom = new FormControl(new Date());
...
}

.html文件,

  <mat-form-field>
    <input matInput [matDatepicker]="dateFrom" [formControl]="dateFrom"
      placeholder="Min date">
    <mat-datepicker-toggle matSuffix [for]="dateFrom"></mat-datepicker-toggle>
    <mat-datepicker #dateFrom ></mat-datepicker>
  </mat-form-field>

基本上,在模板文件中,它不知道要选择哪个“ dateFrom”,而是在模板文件中选择一个,而不是我的打字稿文件中的FormControl,它是{{ 1}}元素。

将FormControl重命名为mat-datepicker可以解决此问题,

dateFromCtrl

... export class MyComponent { dateFromCtrl = new FormControl(new Date()); ... } 文件,

.html

按预期工作。

Kodos使用VS Code来解决这个问题。通过执行Cmd +单击 <mat-form-field> <input matInput [matDatepicker]="dateFrom" [formControl]="dateFromCtrl" placeholder="Min date"> <mat-datepicker-toggle matSuffix [for]="dateFrom"></mat-datepicker-toggle> <mat-datepicker #dateFrom ></mat-datepicker> </mat-form-field> 上的初始'dateFrom',我朝着这个方向发展,它使我指向[formControl]="dateFrom"元素。

答案 11 :(得分:0)

对我来说,发生在我从自动完成输入中使用相同的[formControl]="carBrand"[matAutocomplete]="carBrandAuto"

我改变了

从:

...
<input
  [formControl]="carBrand"
  [matAutocomplete]="carBrand"
>
<mat-autocomplete matAutocomplete #carBrand="matAutocomplete">
...

TO

...
<input
  [formControl]="carBrand"
  [matAutocomplete]="carBrandAuto"
>
<mat-autocomplete matAutocomplete #carBrandAuto="matAutocomplete">
...

答案 12 :(得分:0)

就我而言,当实际表单模型是 FormGroup 实例时,当我在模板中使用 formControlName 时出现错误。更改为 formControlGroup 有帮助。

答案 13 :(得分:-1)

如果在表单中定义了FormArray字段,请注意,您无需使用formControlName =“”对其进行标签。您需要以其他方式(设置程序,获取程序,函数)来处理输入和验证,但是如果您尝试将formControlName分配给FormArray,肯定会出错!