Forms 是什么原因导致了;control.registerOnChange不是一个函数;错误

Forms 是什么原因导致了;control.registerOnChange不是一个函数;错误,forms,angular,Forms,Angular,我有一个使用反应式表单方法的表单。在my pug中创建的表单如下所示: form([formGroup]='form', novalidate='', (ngSubmit)='postSurvey(form.value, form.valid)') 除了我尝试更改javascript部分中的表单(这是一个FormArray)外,其他一切都正常工作。我得到以下错误: EXCEPTION: Error in http://localhost:8080/app/components/fillForm

我有一个使用反应式表单方法的表单。在my pug中创建的表单如下所示:

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上提交了一个问题,并提出了一个修复方案。plunker重现该问题的方法是

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


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

可能您已将模板中的控件元素移到了组之外

好:


密码:
确认:
不正常:

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

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

form: FormGroup = new FormGroup({
  status: new FormArray([])
});
最初,它由模板上每个状态的复选框列表表示。然后我创建了一个自定义组件来表示
状态
选择器,并在模板中使用它,如下所示

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


问题是
formControlName
必须指向
FormControl
实例,但实际上它指向的是
FormArray
实例。因此,更改为
状态:new FormControl([])
为我解决了这个问题。

在混合使用模板驱动和反应驱动方法时,我也遇到了这个错误(错误):



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

如果您在表单中定义了FormArray字段,请注意,您不需要用formControlName=“”标记它。您需要以其他方式(setter、getter、functions)处理输入和验证,但如果尝试将formControlName分配给FormArray,则肯定会出错

当我们在
ng模板
中与
*ngIf
一起使用反应式表单时,也会出现此错误


为了避免这种情况,请使用
ng容器
,不要使用
ngElse

添加在我的情况下导致它的原因

.ts
文件

...

export class MyComponent {
  dateFrom = new FormControl(new Date());
...
}
  <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>
  <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>
.html
文件

...

export class MyComponent {
  dateFrom = new FormControl(new Date());
...
}
  <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>
  <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>
.html
文件

...

export class MyComponent {
  dateFrom = new FormControl(new Date());
...
}
  <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>
  <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>

一切正常


Kodos到VS代码来解决这个问题。通过在
[formControl]=“dateFrom”
处执行Cmd+单击初始的“dateFrom”,我被推到了这个方向,它将我指向
mat datepicker
元素。

在我的例子中,当formControl名称与页面上的模板变量相同时,就会发生错误。比如说

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

<form-status #userStatus ></form-status> //matching template variable name
。。。
//匹配模板变量名

在我的例子中,引发此错误是因为我使用
FormControlName
而不是
FormArrayName
绑定到模板中的
FormArray

我的组件代码:

public form = new FormGroup({
   ...
   checkboxes: new FormArray([....])
})
引发错误的我的模板代码:

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

修正:


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

我改变了这个

发件人:

。。。
...

。。。
...

对于未来的读者,我的问题很简单,它会导致类型错误:control.registerChange不是一个函数

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

myForm:FormGroup=newformgroup({
lname:新表单组({}),
fnam:新的FormGroup({}),
日期:新表单组({}),
});
注意:-出现错误是因为您使用了formControlName
在声明formArray时,必须使用formArray名称


简单解决方案:

在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.');
  }
}

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

我在代码中尝试了这一点。它是有效的。但我不明白为什么它会起作用。“状态”字段为您保存了一个对象数组,对吗?@AngelaPan不,FormArray是一个FormControl-s数组,而不是对象数组。对我来说,我不得不将[formControlName]更改为[formGroupName],但我从这个答案中得到了一些想法。谢谢。@BenKim-那是我的问题。我想弗拉基米尔本可以用formArrayName对我来说这是一个FormGroup的formControlName
<input type="text" formControlName="extensions" />

simple solution: 

<input type="checkbox" formArrayName="extensions" />
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.');
  }
}