Angular自定义响应表单在表单提交时未响应验证



我正在尝试创建一个非常基本的自定义Material reactive表单控件,它只需将三个字段组合在一个对象值中。它工作正常,但当处于无效状态时,它不会显示在表单上,直到单击或更改它。我正在尝试让它在提交父窗体时显示正确的有效状态。

自定义控制

/**
* Interface to define the control value for this input
*/
export interface GuardianInputValues {
id: number;
firstName: string;
lastName: string;
}
/**
* Defines a form control to input a new contact
*/
@Component({
selector: 'sm-guardian-input',
templateUrl: './guardian-input.component.html',
styleUrls: ['./guardian-input.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: MatFormFieldControl,
useExisting: GuardianInputComponent
},
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => GuardianInputComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => GuardianInputComponent),
multi: true
}
]
})
export class GuardianInputComponent implements OnInit, ControlValueAccessor, Validator {
public form: FormGroup;
get value(): GuardianInputValues | null {
if (this.form && this.form.valid) {
return this.form.value;
}
return null;
}
set value(value: GuardianInputValues) {
if (this.form) {
this.form.patchValue(value);
}
}
constructor(
@Optional() private formGroup: FormGroupDirective,
private fb: FormBuilder
) {
this.form = this.fb.group({
id: [null],
firstName: ['', Validators.required],
lastName: ['', Validators.required]
});
this.form.valueChanges.pipe(takeUntil(this.ngUnsubscribe)).subscribe(value => {
this.onChange(value);
this.onTouch();
});
}
public ngOnInit(): void {
this.formGroup.ngSubmit.subscribe(value => {
this.form.get('firstName').markAsTouched();
this.form.get('firstName').markAsDirty();
this.form.updateValueAndValidity();
})
}
public onTouch: any = () => { };
public onChange: any = () => { };
public registerOnTouched(fn: any): void {
this.onTouch = fn;
}
public registerOnChange(fn: any): void {
this.onChange = fn;
}
public writeValue(val: GuardianInputValues): void {
if (val) {
this.value = val;
}
if (val === null) {
this.form.reset();
}
}
public validate(_: AbstractControl): ValidationErrors | null {
return this.form.valid ? null : { profile: { valid: false } };
}
}

控制模板:

<div [formGroup]="form" class="form">
<mat-form-field>
<mat-label>First Name</mat-label>
<input matInput formControlName="firstName" required>
<mat-error *ngIf="form?.get('firstName').hasError('required')">The first name is required.</mat-error>
<mat-form-field>
<mat-label>Last Name</mat-label>
<input matInput formControlName="lastName" required>
<mat-error *ngIf="form?.get('lastName').hasError('required')">The last name is required.</mat-error>
</mat-form-field>
</div>

最后是用法:

this.form = this.fb.group({
email: ['', null, ApiValidator],
prefix: ['', null, ApiValidator],
firstName: ['', Validators.required, ApiValidator],
middleName: ['', null, ApiValidator],
lastName: ['', null, ApiValidator],
suffix: ['', null, ApiValidator],
primaryGuardian: [{
id: null,
firstName: '',
lastName: '',
relation: ''
}, null, ApiValidator]
});
<form [formGroup]="form" *ngIf="initialized">
<div fxLayout="row" id="primaryContactName">
<sm-guardian-input formControlName="primaryGuardian" class="primary-guardian"></sm-guardian-input>
</div>
</form>

我曾试图强制自定义控件的内部表单状态为dirty/tuched,甚至只是设置值,然后将其设置回空以触发验证-什么都做不到。它被标记为无效,只是永远不会被标记为touch/tuched。一旦内部控制真正获得焦点,它也会很好地工作。

提前感谢您的真知灼见。

发生这种情况是因为您已将changeDetection设置为ChangeDetectionStrategy.OnPush

组件GuardianInputComponent中没有@Input成员,因此没有什么可以触发更改检测,但只要您单击输入,更改检测就会运行并呈现错误状态。

删除或将changeDetection更改为ChangeDetectionStrategy.Default应该可以解决问题

或者,您可以在GuardianInputComponent 中强制检测更改

GuardianInputComponent TS

constructor(
@Optional() private formGroup: FormGroupDirective,
private fb: FormBuilder,
private cdr: ChangeDetectorRef,
) { ... }
ngOnInit(): void {
this.formGroup.ngSubmit.subscribe((value) => {
this.form.get('firstName').markAsTouched();
this.cdr.detectChanges()
});
}

最新更新