在我的应用程序中,我使用我的自定义日期时间选择器(它由文本输入和材料日期选择器组成)- 代码如下所示:
<div fxLayoutAlign="center center" fxLayoutGap="10px" [formGroup]="form">
<mat-form-field appearance="outline" class="no-padding no-underline" [class.mat-form-field-invalid]="control?.invalid&&!control.hasError('badTime')" [class.ng-invalid]="control?.invalid&&!control.hasError('badTime')">
<mat-label>{{label}}</mat-label>
<input matInput [matDatepicker]="picker" [max]="max" [min]="min" (dateChange)="changeDate($event)" readonly formControlName="date" (focus)="picker.open()" [errorStateMatcher]="matcher">
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<app-timepicker [test]="control" [showSeconds]="showSec" formControlName="time" [label]="label" (timeChanged)="changeTime($event)" (overMidnight)="onOverMidnight($event)"></app-timepicker>
</div>
此表单控件向外部返回单个值,我最近升级到了 Angular Material 17,并且我在将无效状态从父表单传播到此表单控件时遇到问题。在以前的版本中,我能够至少将无效状态传播为类“mat-form-field-invalid”,我将其与 ngClass 一起使用,并根据传递给组件的 ngControl 进行切换。这不再起作用了。任何想法如何将无效状态从父级传递到自定义表单控件,这将起作用,也许以更优雅的方式? 我尝试了错误状态匹配器,但问题是,无效状态位于父表单上,所以我无法访问它。这是组件的代码:
mport { DatePipe } from '@angular/common';
import { Component, EventEmitter, Input, OnInit, Output, forwardRef } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NgControl, NG_VALUE_ACCESSOR, FormControl, FormGroupDirective, NgForm } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';
@Component({
selector: 'app-datetimepicker',
templateUrl: './datetimepicker.component.html',
styleUrls: ['./datetimepicker.component.scss'],
providers: [
]
})
export class DatetimepickerComponent implements ControlValueAccessor{
matcher = new MyErrorStateMatcher();
value:Date=null;
form:UntypedFormGroup=null;
onChange = (value) => {};
onTouched = () => {};
touched = false;
disabled = false;
init=false;
_disableTime=false;
_disableDate=false;
@Input('disableDate') set disableDate(value:boolean){
this._disableDate=value;
if(value){
this.form.get("date").disable();
}
else{
this.form.get("date").enable();
}
};
@Input('disableTime') set disableTime(value:boolean){
this._disableDate=value;
if(value){
this.form.get("time").disable();
}
else{
this.form.get("time").enable();
}
};
@Input() label:string;
@Input() max:Date;
@Input() min:Date;
@Input() showSec:boolean=false;
@Output() dateChanged:EventEmitter<Date>=new EventEmitter();
constructor(private fb:UntypedFormBuilder, private datePipe:DatePipe, public control:NgControl) {
if (this.control != null) {
this.control.valueAccessor = this;
}
this.form=this.fb.group({
date:[{value:null}],
time:[null]
});
console.log(this.control);
}
get errorState(): boolean {
console.log("check");
return this.control.invalid;
}
writeValue(value: Date): void {
if(value!=null){
this.value=value;
this.form.setValue({
date:value,
time:this.datePipe.transform(value,this.showSec?"HH:mm:ss":"HH:mm")
},{emitEvent:false})
}
}
registerOnChange(onChange: any) {
this.onChange=onChange;
}
registerOnTouched(onTouched: any) {
this.onTouched = onTouched;
}
markAsTouched() {
if (!this.touched) {
this.onTouched();
this.touched = true;
}
}
setDisabledState(disabled: boolean) {
this.disabled = disabled;
}
changeDate(event){
const newDate=new Date(this.value.getTime());
newDate.setDate(event.value.getDate());
newDate.setMonth(event.value.getMonth());
this.value=newDate;
this.onChange(this.value);
console.log("datechanged");
this.dateChanged.emit(this.value);
this.markAsTouched();
}
changeTime(event){
const [hours,minutes,secs]=event.split(":");
console.log(event.split(":"));
const newDate=new Date(this.value.getTime());
if(this.showSec){
newDate.setHours(hours,minutes,secs);
}
else{
newDate.setHours(hours,minutes);
}
this.value=newDate;
this.onChange(this.value);
this.markAsTouched();
}
onOverMidnight(dateChange:number){
const newDate=new Date(this.value.getTime());
if(newDate<=this.max && newDate>=this.min){
newDate.setDate(newDate.getDate()+dateChange);
this.value=newDate;
this.onChange(this.value);
this.form.patchValue({date:this.value});
}
}
}
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
console.log(control);
console.log(form);
return true;
}
}
为了确保父表单的无效状态正确传播到 Angular Material 17 中的自定义表单控件,您需要更有效地集成 ErrorStateMatcher。 :)