【发布时间】:2022-01-26 23:12:51
【问题描述】:
我正在使用 Angular 的 ControlValueAccessor 和 Validator 接口处理 Angular 的出生日期组件。 我已经实现了这些接口所需的所有方法
@Component({
selector: 'app-birthdate',
templateUrl: './birthdate.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => BirthdateComponent)
},
{
provide: NG_VALIDATORS,
multi: true,
useExisting: forwardRef(() => BirthdateComponent)
}
]
})
export class BirthdateComponent implements ControlValueAccessor, OnDestroy, OnInit, Validator {
form!: FormGroup;
birthdayControl!: FormControl;
birthmonthControl!: FormControl;
birthyearControl!: FormControl;
private destroy$ = new Subject<void>();
private onChange = (_birthdatum: string) => {};
private onTouched = () => {};
constructor(private fb: FormBuilder,
private rootFormGroup: FormGroupDirective) {
}
ngOnInit() {
this.form = this.fb.group({
birthday: [null, Validators.required],
birthmonth: [null, Validators.required],
birthyear: [null, Validators.required]
});
this.rootFormGroup.control.addControl('_birthdate', this.form);
this.birthdayControl = this.form.get('birthday') as FormControl;
this.birthmonthControl = this.form.get('birthmonth') as FormControl;
this.birthyearControl = this.form.get('birthyear') as FormControl;
this.form.valueChanges
.pipe(takeUntil(this.destroy$))
.subscribe((birthdate: Geboortedatum) => {
this.markAsTouched();
if (!birthdate.birthday || !birthdate.birthmonth || !birthdate.birthyear) {
return;
}
this.onChange(this.parseDate(birthdate.birthyear, birthdate.birthmonth, birthdate.birthday));
});
}
private markAsTouched(): void {
if (this.birthdayControl.touched && this.birthmonthControl.touched && this.birthyearControl.touched) {
this.onTouched();
}
}
private parseDate(year: number, month: number, day: number): string {
return `${year}-${this.parseDatePart(month)}-${this.parseDatePart(day)}`;
}
private parseDatePart(datePart: number | string): string {
return ('00' + datePart).slice(-2);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
registerOnChange(onChange: (birthday: string) => void): void {
this.onChange = onChange;
}
registerOnTouched(onTouched: () => void): void {
this.onTouched = onTouched;
}
writeValue(birthday: string): void {
if (birthday == null) {
this.birthyearControl.patchValue(null);
this.birthmonthControl.patchValue(null);
this.birthdayControl.patchValue(null);
} else {
this.birthyearControl.patchValue(birthday.slice(0, 4));
this.birthmonthControl.patchValue(birthday.slice(5, 7));
this.geboortedagControl.patchValue(birthday.slice(8));
}
}
setDisabledState(disabled: boolean) {
disabled ? this.form.disable() : this.form.enable();
}
validate(control: AbstractControl): ValidationErrors | null {
const day = this.birthdayControl.value;
const month = this.birthmonthControl.value;
const year = this.birthyearControl.value;
if (!day || !month || !year) {
return null;
}
const parsedDate = this.parseDate(year, month, day);
const birthdate = new Date(parsedDate);
if (birthdate.getFullYear() !== year ||
birthdate.getMonth() + 1 !== month ||
birthdate.getDate() !== day) {
const error = {
validDate: {
value: parsedDate,
day: day,
month: month,
year: year
}
};
this.birthdayControl.setErrors(error);
this.birthmonthControl.setErrors(error);
this.birthyearControl.setErrors(error);
return error;
} else {
this.birthdayControl.updateValueAndValidity({ onlySelf: true, emitEvent: false });
this.birthmonthControl.updateValueAndValidity({ onlySelf: true, emitEvent: false });
this.birthyearControl.updateValueAndValidity({ onlySelf: true, emitEvent: false });
return null;
}
}
}
我遇到的问题是调用父表单方法markAllAsTouched()时内部表单没有更新,所以我将rootFormGroup添加到构造函数并将内部表单添加到父级,但现在所有验证器都在当出生日期的值被更改时,父表单会被调用两次。
我在 ControlValueAccessor 接口上缺少writeStatus 或类似方法。我是不是错过了什么。
【问题讨论】:
标签: angular controlvalueaccessor