1

我有一个要求,用户可以在 datepicker 中选择多个日期,但是在每次选择日期后 mat-datepicker 关闭,我想防止 mat-datepicker 关闭日期选择并在我们单击 datepicker 外部或日历图标时关闭 datepicker .

日期选择器

closed在 mat-datepicker 上尝试了事件,但日期选择器在每个日期选择上闪烁,而且当我们在日期选择器外部单击时它不会关闭。

这是我尝试过的:

html代码:

<input formControlName="fromDate" matInput [matDatepicker]="fromDatePicker" placeholder="From Date" [min]="minDate" readonly>
<mat-datepicker-toggle matSuffix [for]="fromDatePicker"></mat-datepicker-toggle>
<mat-datepicker #fromDatePicker (closed)="_openCalendar(fromDatePicker)"></mat-datepicker>

打字稿代码:

_openCalendar(picker: MatDatepicker<Date>) {
    picker.open();
}
4

3 回答 3

4

我阻止覆盖关闭的方法是更改​​ MatCalendar._userSelected方法。

如果您查看 MatDatePickerContent 的模板,您会注意到发出_userSelection时的调用。调用是关闭覆盖:(_userSelection)="datepicker.close()"。现在,_userSelectionMatCalendar._userSelected中发出。

datepicker.js,第 1687 行,“@angular/material”:“8.2.3”:

_userSelected() {
    this._userSelection.emit();
}

因为我不希望应用程序中的所有 DatePicker 实例都有这种行为,所以在我的组件中我执行了以下操作:

@ViewChild('picker', { static: true }) 
private picker: MatDatepicker<Date>;
private preventCloseOnSelection = true;
private readonly initCalendarUserSelected: () => void;
public model: Array<Date>;

constructor(private readonly cdr: ChangeDetectorRef) {
    this.initCalendarUserSelected = MatCalendar.prototype._userSelected;
}

public ngAfterViewInit() {
    this.picker.calendarHeaderComponent = CalendarTimeHeaderComponent;

    this.picker.openedStream
        .pipe(takeUntil(this.isUnsubscribing))
        .subscribe(() => {

            if (this.preventCloseOnSelection) {
                MatCalendar.prototype._userSelected = () => {};
            } else {
                MatCalendar.prototype._userSelected = this.initCalendarUserSelected;
            }

            this.cdr.detectChanges();
        });
}

public ngOnDestroy() {
    MatCalendar.prototype._userSelected = this.initCalendarUserSelected;
}

如果您希望日期选择器的所有实例都具有此行为,则可以在 AppComponent 中的某处覆盖MatCalendar._userSelected方法,而不必费心恢复它。

另一种方法是this.picker.close = () => { };在日期更改后执行,但您必须始终恢复它才能关闭覆盖。

您可以使用matDatepickerInput 的 dateChange事件获取选定的日期,并创建一个包含多个值的日期的数组,并在视图中选择它们,您可以使用matDatepicker的dateClass输入。

看法:

<input [(ngModel)]="model" matInput [matDatepicker]="picker" placeholder="Choose a date" (dateChange)="dateChanged($event)" />
<mat-datepicker-toggle matPrefix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker [dateClass]="dateClass"></mat-datepicker>

方法:

public dateClass = (date: Date) => {
    if (this.model.map((m) => +m).indexOf(+date) !== -1) {
        return [ 'selected' ];
    }
    return [ ];
}

public dateChanged(event: MatDatepickerInputEvent<Date>) {
    if (event.value) {
        const date = event.value;
        const index = this.model.map((m) => +m).indexOf(+date);
        if (index === -1) {
            this.model.push(date);
        } else {
            this.model.splice(index, 1)
        }
    }
}
于 2020-01-31T14:53:18.910 回答
0

在日期范围选择器的情况下,我解决了这个问题,如下所示:

export class MatDatetimeComponent {
  @ViewChild(MatDateRangePicker) containerElRef;

  constructor(
    private resolver: ComponentFactoryResolver,
    private cdr: ChangeDetectorRef,
    private cdkConnectedOverlay: OverlayOutsideClickDispatcher
  ) {}

  // store prototype close object
  private selfClose: () => void;

  ngAfterViewInit() { 
    this.selfClose = this.containerElRef.close;
  }
  public onOpen() { 
    // rewrite autoclose after date is chosen
    this.containerElRef.close = () => {};

    // close calendar manually on outside click
    this.cdkConnectedOverlay._attachedOverlays[0]._outsidePointerEvents.subscribe(() => {
        // restore saved close method
        this.containerElRef.close = this.selfClose;
        this.containerElRef.close();
    });
  }
}
于 2021-01-10T15:05:57.187 回答
0

因为其他解决方案对我不起作用,所以我这样做了:

打字稿代码:

  @ViewChild(MatDatepicker) datePicker: MatDatepicker<Date>;

  constructor(
    private changeDetectorRef: ChangeDetectorRef,
    private cdkConnectedOverlay: OverlayOutsideClickDispatcher) { }

  // store prototype close object
  private selfClose: () => void;

  opened() {
    if (isNullOrUndefined(this.selfClose)) {
      this.selfClose = this.datePicker.close;
    }

    // rewrite autoclose after date is chosen
    this.datePicker.close = () => {};

    // close calendar manually on outside click
    this.cdkConnectedOverlay._attachedOverlays[0]._outsidePointerEvents.subscribe(() => {
      // restore saved close method
      this.datePicker.close = this.selfClose;
      this.selfClose = undefined;
      this.datePicker.close();
    });
  }

架构代码:

  <mat-datepicker #picker
                  (opened)="opened()"
  ></mat-datepicker>

也许这可以帮助那里的人。

于 2021-05-17T12:41:10.820 回答