DEV Community

Paul Laros πŸ‡³πŸ‡±
Paul Laros πŸ‡³πŸ‡±

Posted on • Originally published at laros.io on

Using Angular Material's calendar with date ranges and range presets

Image description

Angular Material's calendar component is a valuable tool for handling date ranges in Angular applications. However, the existing documentation may be limited, and online examples often lack completeness or rely on unconventional methods, that's why we've decided to write this blog post.

While this post won't be a step-by-step tutorial, we'll explain all the relevant parts. Additionally, you can find a complete implementation, including the custom range preset buttons, on StackBlitz.

Getting Started

We assume you're already familiar with Angular Material and the calendar component but are running into issues while setting it up to handle date ranges and custom date range presets. If you're not, no worries! You can start by checking out the official documentation on Angular Material's website.

Setting Up Providers

To begin, we need to set up the necessary providers for the Angular Material calendar component. These providers enable the preview functionality. Here's an example of how to set up the providers:

import {
  DefaultMatCalendarRangeStrategy,
  MatRangeDateSelectionModel,
} from '@angular/material/datepicker';

@Component({
  ...,
  providers: [DefaultMatCalendarRangeStrategy, MatRangeDateSelectionModel],
})
Enter fullscreen mode Exit fullscreen mode

Handling Date Range Selection

Next, let's implement the event handler for when the date range selection changes. This handler will be triggered when a user clicks on a date in the calendar. Here's an example implementation:

selectedDateRange: DateRange<Date> | undefined;

constructor(
  private readonly selectionModel: MatRangeDateSelectionModel<Date>,
  private readonly selectionStrategy: DefaultMatCalendarRangeStrategy<Date>,
) { }

// Event handler for when the date range selection changes.
rangeChanged(selectedDate: Date) {
  const selection = this.selectionModel.selection,
    newSelection = this.selectionStrategy.selectionFinished(
      selectedDate,
      selection
    );

  this.selectionModel.updateSelection(newSelection, this);
  this.selectedDateRange = new DateRange<Date>(
    newSelection.start,
    newSelection.end
  );
}
Enter fullscreen mode Exit fullscreen mode

By updating the selection model and assigning the new date range to selectedDateRange, we can ensure that the selected range is accurately reflected in the UI.

Make sure to update your template as well:

html

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

Enter fullscreen mode Exit fullscreen mode

That's it! By following the steps outlined above, you should now have a fully functional calendar component capable of handling date ranges.

Creating Custom Date Range Presets

To enhance the user experience, we can implement custom date range presets. These presets allow users to quickly select commonly used date ranges without manually selecting individual dates. Here's an example configuration for presets:

presets = [
  {
    label: 'Today',
    range: {
      start: new Date(),
      end: new Date(),
    },
  },
  {
    label: 'Last 7 days',
    range: {
      start: (() => {
        const date = new Date();
        date.setDate(date.getDate() - 7);
        return date;
      })(),
      end: new Date(),
    },
  },
  {
    label: 'Last 30 days',
    range: {
      start: (() => {
        const date = new Date();
        date.setDate(date.getDate() - 30);
        return date;
      })(),
      end: new Date(),
    },
  },
  ...
]
Enter fullscreen mode Exit fullscreen mode

Make sure to render the available presets in your template, allowing users to select them with a single click:

<button
  *ngFor="let preset of presets"
  (click)="selectPreset(preset.range)"
>
  {{ preset.label }}
</button>
Enter fullscreen mode Exit fullscreen mode

To handle the preset selection, include a preset handler like the following example. This handler sets the selected date range and ensures that the calendar navigates to the month where the start date lies:

selectPreset(presetDateRange: { start: Date; end: Date }) {
  this.selectedDateRange = new DateRange<Date>(
    presetDateRange.start,
    presetDateRange.end
  );

  // Jump into month of presetDateRange.start
  if (presetDateRange.start && this.calendar)
    this.calendar._goToDateInView(presetDateRange.start, 'month');
}
Enter fullscreen mode Exit fullscreen mode

Try it Yourself

And there you have it! With the steps outlined in this post, you're well-equipped to use Angular Material's calendar component with date ranges and custom presets. Remember, if you want to see a complete implementation, including the custom range preset buttons, check out the StackBlitz example provided.

Top comments (0)