将无效状态传播到自定义表单控件

问题描述 投票:0回答:1

在我的应用程序中,我使用我的自定义日期时间选择器(它由文本输入和材料日期选择器组成)- 代码如下所示:

<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;
  }
}
javascript angular angular-material
1个回答
0
投票

为了确保父表单的无效状态正确传播到 Angular Material 17 中的自定义表单控件,您需要更有效地集成 ErrorStateMatcher。 :)

© www.soinside.com 2019 - 2024. All rights reserved.