首页 > 解决方案 > 如何使用角材料实现范围内联日历?

问题描述

我想使用材料日历作为范围内联日历来显示和插入日期范围。使用 mat-date-range-picker 时,这只是工作(但不是内联)。使用 mat-calendar 时,它适用于内联,但不适用于远程。但是,如果我将 selectedRangeValue 作为 DateRange 而不是 Date 传递,则 Range 会正确显示。

唯一仍然缺少的是输入...

这是我现在使用的代码(缩写):

<mat-calendar (selectedChange)="selectedRangeChange($event)"
              [selected]="selectedRangeValue"
>
</mat-calendar>
selectedRangeValue: DateRange<Date> =  new DateRange<Date>(this.selectedValue.begin, this.selectedValue.end);

我必须这样做,因为土星日期选择器仅在 Angular 9 之前受支持,而从 Angular 10 开始,Material Datepicker 支持日期范围。但是这个“内联日期范围日历”我只是无法工作......

我发现https://github.com/angular/components/issues/20697描述了同样的问题并找到了解决方案,但没有写下来,所以没有帮助。

我也试着去了解angular material datepicker的源码,可惜还是没搞懂。我将不胜感激任何帮助或提示。

标签: angularangular-material

解决方案


我找到了解决这个问题的方法。虽然我不确定这是否是最好的方法,但我想提供解决方案。

我必须为内联范围日历创建一个新的角度组件:

HTML 架构

<mat-calendar
  #calendar
  [selected]="selectedRangeValue"
  (selectedChange)="selectedChange($event)"
>
</mat-calendar>

打字稿

import {Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
import {
  DateRange, DefaultMatCalendarRangeStrategy,
  MAT_DATE_RANGE_SELECTION_STRATEGY, MatCalendar,
} from '@angular/material/datepicker';
import {isNullOrUndefined} from '../../util/is-null-or-undefined';
import moment from 'moment';

@Component({
  // tslint:disable-next-line:component-selector
  selector: 'inline-range-calendar',
  templateUrl: './inline-range-calendar.component.html',
  styleUrls: ['./inline-range-calendar.component.sass'],
  providers: [{
    provide: MAT_DATE_RANGE_SELECTION_STRATEGY,
    useClass: DefaultMatCalendarRangeStrategy
  }]
})
export class InlineRangeCalendarComponent implements OnInit {

  @ViewChild(MatCalendar) calendar: MatCalendar<Date>;

  @Input() selectedRangeValue: DateRange<Date>;
  @Output() selectedRangeValueChange = new EventEmitter<DateRange<Date>>();

  ngOnInit(): void {
 }

selectedChange($event) {
const m = moment($event);

if (!isNullOrUndefined(this.selectedRangeValue.end)) {
  const start = this.selectedRangeValue.start;
  // @ts-ignore the parser thinks that this is a date, but it is a moment.js object, so this will work
  start.set(m.toObject());
  this.selectedRangeValue = new DateRange<Date>(start, undefined);
  this.selectedRangeValueChange.emit(this.selectedRangeValue);
} else {
  const end = (!isNullOrUndefined(this.selectedRangeValue.end)) ? this.selectedRangeValue.end : moment(m);
  // @ts-ignore the parser thinks that this is a date, but it is a moment.js object, so this will work
  end.set(m.toObject());
  // @ts-ignore the parser thinks that this is a date, but it is a moment.js object, so this will work
  this.selectedRangeValue = new DateRange<Date>(this.selectedRangeValue.start, end);
  if (this.selectedRangeValue.end < this.selectedRangeValue.start)  {
    this.selectedRangeValue = new DateRange<Date>(this.selectedRangeValue.end, this.selectedRangeValue.start);
  }
  this.selectedRangeValueChange.emit(this.selectedRangeValue);
}
}

}

希望这可以帮助某人。


推荐阅读