我正在尝试实现角度反应嵌套表单。我的表单工作正常,但在加载表单时 我收到以下错误。我的表单正在正确验证,我能够访问我的嵌套值。但在 初始加载我收到以下错误,因为它没有正确呈现。
ERROR TypeError: control.registerOnChange is not a function
at setUpModelChangePipeline (forms.js:1689)
at setUpControl (forms.js:1511)
at FormGroupDirective.addControl (forms.js:5253)
at FormControlName._setUpControl (forms.js:5835)
at FormControlName.ngOnChanges (forms.js:5780)
at FormControlName.rememberChangeHistoryAndInvokeOnChangesHook (core.js:1520)
at callHook (core.js:2583)
at callHooks (core.js:2542)
at executeInitAndCheckHooks (core.js:2493)
at selectIndexInternal (core.js:8463)
父组件 Html
<form [formGroup]="studentForm">
<h4>Student Details</h4>
<mat-form-field>
<label>Name</label>
<input matInput type="text" name="name" formControlName="name"><br>
<mat-error *ngIf="name.errors?.required">Name is required</mat-error>
<mat-error *ngIf="name.errors?.minlength">Name should be minimum {{name.errors?.minlength.requiredLength}} characters</mat-error>
<mat-error *ngIf="name.errors?.maxlength">Name should be maximum {{name.errors?.maxlength.requiredLength}} characters</mat-error>
</mat-form-field>
<br>
<mat-form-field>
<label>Age</label>
<input matInput type="text" formControlName="age"><br>
<mat-error *ngIf="age.errors?.required">Age is required</mat-error><br>
</mat-form-field>
<ng-container *ngIf="age.errors | displayOneError: ['required','minlength','minor'] as error">
<div *ngIf="error?.minlength">Age should be minimum {{error?.minlength.requiredLength}} characters</div><br>
<div *ngIf="error?.minor">Age should be greater than 18</div><br>
</ng-container>
<br>
<!-- {{age.errors | json}} -->
<mat-form-field>
<label>Email</label>
<input matInput type="text" formControlName="email"><br>
<mat-error *ngIf="email.errors?.required">Email is required</mat-error>
<mat-error *ngIf="email.errors?.email">Email is invalid</mat-error>
</mat-form-field>
<br>
<app-addresscomponent formControlName="addressForm"></app-addresscomponent>
<input type="button" value="Submit" [disabled]="!studentForm.valid" (click)="save()"/>
{{studentForm.value | json}}
{{studentForm.errors | json}}
</form>
Parent Component TS
import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { ApiBuilderService } from '../builder/api-builder-service';
import { Student } from '../model/student';
import { createMinorAgeValidator } from '../validators/age-validator';
@Component({
selector: 'app-embeddedform',
templateUrl: './embeddedform.component.html',
styleUrls: ['./embeddedform.component.scss']
})
export class EmbeddedformComponent implements OnInit {
studentForm = this.fb.group({
name : ['',{
validators : [Validators.required, Validators.minLength(3), Validators.maxLength(50)],
updateOn : 'blur'
}],
age : ['', {
validators : [Validators.required, Validators.minLength(2), createMinorAgeValidator()],
updateOn : 'blur'
}],
email : ['', {
validators : [Validators.required, Validators.minLength(3), Validators.maxLength(50)],
updateOn : 'blur'
}],
addressForm : this.fb.group({
city : ['',{
validators : [Validators.required, Validators.minLength(3), Validators.maxLength(50)],
updateOn : 'blur'
}],
state : ['', {
validators : [Validators.required, Validators.minLength(3), Validators.maxLength(50)],
updateOn : 'blur'
}],
})
});
constructor(private fb : FormBuilder, private apiBuilderService : ApiBuilderService) { }
ngOnInit(): void {
}
get name() {
return this.studentForm.controls['name'];
}
get age() {
return this.studentForm.controls['age'];
}
get email() {
return this.studentForm.controls['email'];
}
save() {
let student : Student = {...this.studentForm.getRawValue()};
alert(JSON.stringify(student));
alert(JSON.stringify(this.apiBuilderService.buildStudentRequest(student)));
}
}
Child Component:
import { Component, forwardRef, OnDestroy, OnInit, StaticProvider } from '@angular/core';
import { Validators, FormBuilder, ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, RequiredValidator, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
import { Subscription } from 'rxjs';
import { Address } from '../model/address';
@Component({
selector: 'app-addresscomponent',
templateUrl: './addresscomponent.component.html',
styleUrls: ['./addresscomponent.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi:true,
useExisting: AddresscomponentComponent
},
]
})
export class AddresscomponentComponent implements OnInit, ControlValueAccessor,OnDestroy, Validator {
addressForm = this.fb.group({
city : ['',{
validators : [Validators.required, Validators.minLength(3), Validators.maxLength(50)],
updateOn : 'blur'
}],
state : ['', {
validators : [Validators.required, Validators.minLength(3), Validators.maxLength(50)],
updateOn : 'blur'
}],
});
onTouched = () => {};
onValidated = () => {};
onChangeSub: Subscription;
constructor(private fb : FormBuilder) { }
validate(control: AbstractControl): ValidationErrors {
return this.addressForm.valid? null:{invalidForm : { valid : false, message : "Invalid Address Form"}};
}
registerOnValidatorChange?(onValidated: () => void): void {
this.onValidated = onValidated;
}
ngOnDestroy(): void {
this.onChangeSub.unsubscribe();
}
writeValue(value: any): void {
if (value) {
this.addressForm.setValue(value);
}
}
registerOnChange(onChange: any): void {
this.onChangeSub = this.addressForm.valueChanges.subscribe(onChange);
}
registerOnTouched(onTouched: any): void {
this.onTouched = onTouched;
}
setDisabledState(disabled:boolean) {
if (disabled) {
this.addressForm.disable();
}
else {
this.addressForm.enable();
}
}
}
Child Component Html
<form [formGroup]="addressForm">
<h4>Address Details</h4>
<mat-form-field>
<label>City</label>
<input matInput type="text" name="city" formControlName="city" (blur)="onTouched()"><br>
<mat-error *ngIf="city.errors?.required">City is required</mat-error>
<mat-error *ngIf="city.errors?.minlength">City should be minimum {{city.errors?.minlength.requiredLength}} characters</mat-error>
<mat-error *ngIf="city.errors?.maxlength">City should be maximum {{city.errors?.maxlength.requiredLength}} characters</mat-error>
</mat-form-field>
<br>
<mat-form-field>
<label>State</label>
<input matInput type="text" name="state" formControlName="state" (blur)="onTouched()"><br>
<mat-error *ngIf="state.errors?.required">State is required</mat-error>
<mat-error *ngIf="state.errors?.minlength">State should be minimum {{state.errors?.minlength.requiredLength}} characters</mat-error>
<mat-error *ngIf="state.errors?.maxlength">State should be maximum {{state.errors?.maxlength.requiredLength}} characters</mat-error>
</mat-form-field>
<br>
</form>
为什么我在加载时遇到 registerOnChange 错误。任何帮助将不胜感激!!!