網站搜尋

angular - 如何將控制封裝到自訂 ControlValueAccessor 並遵守驗證規則


我有一個 matDatePicker,我在整個應用程式中使用反應式表單,如下所示:

<mat-form-field>
    <input formControlName="ratingDate" matInput [matDatepicker]="picker1" 
         placeholder="Rating Date" (dateInput)="performnCustomValidation)">
    <mat-datepicker-toggle matSuffix [for]="picker1"></mat-datepicker-toggle>
    <mat-datepicker #picker1></mat-datepicker>
</mat-form-field>

然而,有一個驗證錯誤,我需要通過一些額外的事件處理來解決:

performnCustomValidation(event: MatDatepickerInputEvent<Date>) {
  var strValue = (event.targetElement as HTMLInputElement).value
  if (event.value === null && strValue) {
    this.dateFormControl.setErrors({ isDate: true }, { emitEvent: true});
  }
}

所以我決定把這個包裝成自訂控制項。

我該如何讓驗證在我的自訂包裝元件中像以前一樣運作?

那意味著它必須尊重

  1. 內建 matDatePicker 驗證
  2. FormControl 驗證器
  3. 我的自訂驗證錯誤
  4. 驗證狀態必須以與之前相同的視覺效果呈現

到目前為止我有這個,但沒有驗證

@Component({
  selector: 'app-date-picker',
  template: `
<mat-form-field class="large-input" floatLabel="always">
    <input #input1 matInput [matDatepicker]="picker1" (dateChange)="performCustomValidation($event)">
  <mat-datepicker-toggle matSuffix [for]="picker1"></mat-datepicker-toggle>
  <mat-datepicker #picker1></mat-datepicker>
</mat-form-field>`,
  styleUrls: ['./date-picker.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => DatePickerComponent),
      multi: true
    }
  ]
})
export class DatePickerComponent implements ControlValueAccessor, AfterViewInit {

  @ViewChild(MatInput) matInput;
  @ViewChild('input1') input;


  private control: FormControl;

  onChange: any = (date: Date) => { };
  onTouched: any = () => { };

  constructor(private injector: Injector,
  ) {

   }

  // The form control is only set after initialization
  ngAfterViewInit(): void {
    const ngControl: NgControl = this.injector.get(NgControl, null);
    if (ngControl) {
      this.control = ngControl.control as FormControl;
    } else {
    }
  }


  performnCustomValidation(event: MatDatepickerInputEvent<Date>) {
    var strValue = (event.targetElement as HTMLInputElement).value
    if (event.value === null && strValue) {
      this.dateFormControl.setErrors({ isDate: true }, { emitEvent: true});
    }
  }

  writeValue(value) {
    this.matInput.value = value;
  }

  registerOnChange(fn) {
    this.onChange = fn;
  }
  // We implement this method to keep a reference to the onTouched
  //callback function passed by the forms API
  registerOnTouched(fn) {
    this.onTouched = fn;
  }
}