Angular Material Datepicker begrenzen die Bereichsauswahl

Oct 25 2020

Ich habe eine eckige Material-Datumsauswahl für Bereiche (Startdatum und Enddatum).

Derzeit ist es freie Auswahl. Das heißt, ich kann jedes Startdatum und jedes Enddatum auswählen. Ich würde es gerne ein bisschen ändern. Ich möchte, dass der Unterschied auf bis zu 7 Tage begrenzt wird. Ich möchte dem Benutzer nicht erlauben, 2 Daten mit einer Differenz von mehr als 7 Tagen auszuwählen.

Also im Kalender: es sieht ungefähr so ​​aus

Wie Sie sehen können, ist der 5. Oktober das Startdatum, und wir können den 17. Oktober als Enddatum auswählen. Ich möchte jedoch, dass der Benutzer das Enddatum nur im Bereich vom 5. Oktober bis 12. Oktober (maximal 7 Tage Differenz) auswählen kann.

Gibt es einen Weg?

Das ist mein HTML:

<mat-form-field class="datepicker" appearance="fill">
    <mat-label>Enter a date range</mat-label>
    <mat-date-range-input [formGroup]="rangeForm" [rangePicker]="picker" [max]="maxDate">
        <input matStartDate formControlName="start" placeholder="Start date" readonly>
        <input matEndDate formControlName="end" placeholder="End date" readonly>
    </mat-date-range-input>

Typoskript:

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import * as moment from 'moment';

@Component({
    selector: 'app-chart',
    templateUrl: './chart.component.html',
    styleUrls: ['./chart.component.scss']
})
export class ChartComponent implements OnInit {
    private _startDate: moment.Moment = moment().subtract(6, 'days');
    private _endData: moment.Moment = moment();
    
    public maxDate: Date = this._endData.toDate();
    public rangeForm: FormGroup = new FormGroup({
        start: new FormControl(this._startDate.toDate()),
        end: new FormControl(this._endData.toDate()),
    });
    
    constructor() { }
    
    ngOnInit(): void {
    }
    
    /**
    * Getter for start date
    * @returns string
    */
    public getStartDate(): string {
        return this._startDate.format('DD/MM/YYYY');
    }
    
    /**
    * Getter for end date
    * @returns string
    */
    public getEndDate(): string {
        return this._endData.format('DD/MM/YYYY');
    }
    
}

Antworten

Eliseo Oct 25 2020 at 18:24

Implementieren einer MatDateRangeSelectionStrategy,

Wir schaffen einen Anbieter wie

@Injectable()
export class MaxRangeSelectionStrategy<D>
  implements MatDateRangeSelectionStrategy<D> {
  start: any;
  constructor(@Inject('rangeMax') private delta: number,
    private _dateAdapter: DateAdapter<D>
  ) {}

selectionFinished(date: D, currentRange: DateRange<D>) {
    let {start, end} = currentRange;
    if (start == null || (start && end)) {
      start = date;
      end=null;
    } else if (end == null) {
      const maxDate=this._dateAdapter.addCalendarDays(start, this.delta);
      end=date?date>maxDate?maxDate:date:null;
    }

    return new DateRange<D>(start, end);
  }
createPreview(activeDate: D | null, currentRange: DateRange<D>): DateRange<D> {
      if (currentRange.start && !currentRange.end) {
      const maxDate=this._dateAdapter.addCalendarDays(currentRange.start, this.delta);
      const rangeEnd=activeDate?activeDate>maxDate?maxDate:activeDate:null;
        return new DateRange(currentRange.start, rangeEnd);
      }

    return new DateRange<D>(null, null);
  }

  }

Sie können direkt in Ihrer Komponente wie verwenden

@Component({
  selector: "date-range-picker-selection-strategy-example",
  templateUrl: "date-range-picker-selection-strategy-example.html",
  providers: [
    {provide: 'rangeMax', useValue: 5},
    {
      provide: MAT_DATE_RANGE_SELECTION_STRATEGY,
      useClass: MaxRangeSelectionStrategy
    }
  ]
})
export class DateRangePickerSelectionStrategyExample {}

Es ist jedoch besser, eine Richtlinie zu erstellen (nicht vergessen, in Ihrem Modul zu deklarieren).

Ersetzen Sie dazu zunächst den Konstruktor der MaxRangeSelectionStrategy, um @Inject('rangeMax')die Variable Delta zu entfernen und zu deklarieren:

  public delta: number; //<--get out of constructor and make public
  constructor(private _dateAdapter: DateAdapter<D>) {}

Erstellen Sie nun die Direktive:

@Directive({
  selector: "[maxRange]",
  providers: [
    {
      provide: MAT_DATE_RANGE_SELECTION_STRATEGY,
      useClass: MaxRangeSelectionStrategy
    }
  ]
})
export class MaxRangeDirective {
  constructor(
    @Inject(MAT_DATE_RANGE_SELECTION_STRATEGY)
    private maxRangeStrategy: MaxRangeSelectionStrategy<any>
  ) {}
  @Input() set maxRange(value: number) {
    this.maxRangeStrategy.delta = +value || 7;
  }
}

Und in der .html verwenden

  <mat-date-range-picker maxRange=5 #picker></mat-date-range-picker>

Endlich können wir in styles.scss eine .css-ähnliche hinzufügen

.mat-calendar-body-preview-end> .mat-calendar-body-cell-content {
  background-color: rgba(0, 0, 0, 0.04)!important;
}

Das letzte Element als ausgewählt markieren

Siehe das Stackbliz