角度材质撰写日期选择器组件

时间:2018-06-06 21:27:11

标签: angular datepicker angular-material

Stackblitz example

我想编写一个包含Material Date Picker实现的组件,以简化在整个应用程序中使用日期组件的过程。我有一点工作,但混合模板驱动和反应形式代码,这从来都不是一个好主意,现在发出警告,它已被弃用。所以我试图只使用ngModel重写。但是,我无法使验证在初始加载时正常工作。它总是会产生必要的字段错误。

HTML

 <mat-form-field style="width:inherit">
  <input id="DatePickerControlInput" name="datePickerControlInput" #aocDatePickerControl="ngModel" (ngModelChange)="change($event)"
         matInput [matDatepicker]="picker" [required]="required"
         [placeholder]="label" [(ngModel)]="innerValue" (blur)="onBlur($event)" (dateChange)="onDateChange($event)" [max]="maxDate">
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-datepicker #picker></mat-datepicker>
  <mat-error *ngIf="aocDatePickerControl.invalid && (aocDatePickerControl.dirty || aocDatePickerControl.touched)">
    <div *ngIf="aocDatePickerControl.errors.required && !aocDatePickerControl.errors.matDatepickerParse">Required field</div>
    <div *ngIf="aocDatePickerControl.errors.matDatepickerMax">Date cannot be in the future</div>
    <div *ngIf="aocDatePickerControl.errors.matDatepickerParse">Not a valid date</div>
  </mat-error>
</mat-form-field>

打字稿

import { Component, OnInit, OnChanges, forwardRef, HostBinding, Input, ViewChild, ElementRef } from '@angular/core';
import {
  ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormControl,
  Validator, Validators, ValidatorFn, AbstractControl, NgModel
} from '@angular/forms';
import * as moment from 'moment';

@Component({
  selector: 'aoc-date-picker',
  templateUrl: './CustomDatePicker.component.html',
  providers: [
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => AocDatePickerComponent),
      multi: true
    },
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => AocDatePickerComponent),
      multi: true
    }
  ]
})
export class AocDatePickerComponent implements OnInit, OnChanges, ControlValueAccessor, Validator {

  @ViewChild(NgModel) aocDatePickerControl: NgModel;
  @ViewChild('aocDatePickerControl', { read: ElementRef }) inputControl: ElementRef;

  @Input() label = 'Choose a date';
  @Input() required?= false;
  @Input() disabled?= false;
  @Input() autofocus?= false;
  @Input() allowFutureDates?= true;

  maxDate;

  innerValue;

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

  constructor() { }

  focus() {
    this.inputControl.nativeElement.focus();
  }

  ngOnInit() {
  }

  ngOnChanges() {
    this.maxDate = this.allowFutureDates ? null : new Date();
  }

  writeValue(value: any) {
    this.innerValue = value;

    // this.aocDatePickerControl.control.setValue(this.innerValue);
    // this.aocDatePickerControl.control.updateValueAndValidity();
    // this.aocDatePickerControl.model = value;
    // this.aocDatePickerControl.valueAccessor.writeValue(value);
  }

  // This needs to be wired to the dateChange event and not dateInput event so that
  // the changed value is only bubbled up when the user changes focus or selects from
  // the popup calendar and not on each key stroke
  onDateChange(event) {
    this.onChange(event.value);
  }

  registerOnChange(fn: (value: any) => void) {
    this.onChange = fn;
  }

  registerOnTouched(fn: any) {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean) {
    this.disabled = isDisabled;
    if (isDisabled) {
      this.aocDatePickerControl.control.disable();
    } else {
      this.aocDatePickerControl.control.enable();
    }
  }

  validate(control: FormControl) {
    const errors = Object.assign({}, this.aocDatePickerControl.errors || {});
    return Object.keys(errors).length && this.aocDatePickerControl.invalid ? errors : null;
  }

  onBlur($event) {
    if ($event.target && $event.target.value && $event.target.value.length === 8 && !isNaN($event.target.value)) {
      const val: String = $event.target.value;
      const month = val.slice(0, 2);
      const day = val.slice(2, 4);
      const year = val.slice(4);
      this.innerValue = new Date(`${ month }/${ day }/${ year }`);
      this.aocDatePickerControl.control.setValue(this.innerValue);
      this.aocDatePickerControl.control.updateValueAndValidity();
      this.onChange(this.innerValue);
    }
    if (this.aocDatePickerControl.hasError('matDatepickerParse')) {
      this.aocDatePickerControl.control.setValue(null);
      this.aocDatePickerControl.control.updateValueAndValidity();
    }

    this.onTouched();
  }
}

1 个答案:

答案 0 :(得分:0)

我在Material Github网站上发布了一个修复我的问题的问题。基本上,对于这样的事情,反应形式更好。这是评论和更新的stackblitz的链接。

在这种情况下,通过反应控制更容易处理状态:Updated StackBlitz