我目前面临着无限调用处理表单验证的 Angular 组件中的 getter 方法的问题。 getter 用于确定表单控件的有效性,但由于 Angular 的更改检测机制,它似乎会导致无限循环。
text-input.component.ts
import { CommonModule } from '@angular/common';
import { IonLabel, IonInput } from '@ionic/angular/standalone';
import { Component, inject, Input, OnDestroy, OnInit } from '@angular/core';
import { ControlContainer, FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
standalone: true,
selector: 'app-text-input',
imports: [ReactiveFormsModule, IonLabel, IonInput, CommonModule],
viewProviders: [
{
provide: ControlContainer,
useFactory: () => inject(ControlContainer, { skipSelf: true }),
},
],
template: `
<div class="input-section ion-padding-top">
<!-- label -->
<ion-label class="input-label">
{{ label }}
@if (required) {
<span class="required-star">*</span>
}
</ion-label>
<!-- input -->
<ion-input
mode="md"
fill="outline"
[ngClass]="inputClass"
[placeholder]="placeholderText"
[formControlName]="controlName"
/>
<!-- validation -->
@if (isControlInvalid) {
<ion-label class="invalid-label">Please enter the {{ label.toLowerCase() }}.</ion-label>
}
</div>
`,
})
export class TextInputComponent implements OnInit, OnDestroy {
@Input() required = true;
@Input() formSubmitted = false;
@Input({ required: true }) label = '';
@Input({ required: true }) controlName = '';
@Input({ required: true }) placeholderText = '';
constructor(
private formBuilder: FormBuilder,
private parentContainer: ControlContainer,
) {}
get parentFormGroup() {
return this.parentContainer.control as FormGroup;
}
// Getter to check if the control is invalid
get isControlInvalid() {
console.log('called 1');
return this.formSubmitted && this.parentFormGroup.get(this.controlName)?.invalid;
}
// Getter to get the input class
get inputClass() {
console.log('called 2');
return this.isControlInvalid ? 'invalid-input' : 'valid-input';
}
ngOnInit() {
this.parentFormGroup.addControl(this.controlName, this.formBuilder.control('', Validators.required));
}
ngOnDestroy() {
this.parentFormGroup.removeControl(this.controlName);
}
}
parent.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
})
export class ParentComponent implements OnInit {
eventForm!: FormGroup;
formSubmitted: boolean = false;
constructor(private fb: FormBuilder) {}
ngOnInit() {
// automatically add the location when call the app-text-input component
this.eventForm = this.fb.group({});
}
}
parent.component.html
<form [formGroup]="eventForm">
<app-text-input
label="Venue"
controlName="location"
[formSubmitted]="formSubmitted"
placeholderText="Venue Name" />
</form>
我可以采取什么策略来防止无限调用 getter 方法?在这种情况下,是否有以 Angular 反应形式管理状态的最佳实践可以提供帮助?
每个变更检测周期都会调用 getter 方法,您可以尝试
ChangeDetectionStrategy.OnPush
减少调用次数,这将减少变更检测周期的数量。
@Component({
standalone: true,
selector: 'app-text-input',
imports: [ReactiveFormsModule, IonLabel, IonInput, CommonModule],
changeDetection: ChangeDetectionStrategy.OnPush
})