User interface
Angular Components HTML Material RxJS SPA Typescript Visual Studio Code

How to use the Angular Date Range Picker Component

Welcome to today’s post.

In today’s post I will be showing how to use the Angular 10 Material Date Range Picker Component. Before Material 10, there was no Date Range Picker Component within the Material Library, and we would have had to use other third-party packages to achieve this functionality. One such third party library you could use for Angular 8 onwards is the angular-material-components/datetime-picker NPM library.

With Angular 10, a date range picker component is included. The full reference for the Date Picker component is in the Angular Material site.

In one of my previous posts, I showed how to use the Material Date Picker component within Angular applications. In that post, I showed how to render a Material Date Picker, allow user input date selection, and read date values from the picker using Typescript. 

Explaining the Date Range Picker Component

The Date Range Picker differs from a normal date picker in that it contains an additional date picker control that allows the user to select an earlier (a from) and a later (a to) date. 

In the HTML template we are using the Date Picker, the Date Range Picker is declared using the HTML tag <mat-date-range-input> as shown:

<mat-form-field>
    <mat-label>Date Range</mat-label>

    <mat-date-range-input [rangePicker]="picker">
        <input type="text" name="dateRangeStart" id="dateRangeStart"  
            matStartDate placeholder="Start date" 
            (dateInput)="dateRangeChanged($event)" 
            (dateChange)="dateRangeChanged($event)">

        <input type="text" name="dateRangeEnd" id="dateRangeEnd"  
            matEndDate placeholder="End date"
            (dateInput)="dateRangeChanged($event)" 
            (dateChange)="dateRangeChanged($event)">
    </mat-date-range-input>
     
    <mat-datepicker-toggle matSuffix [for]="picker">
    </mat-datepicker-toggle>

    <mat-date-range-picker #picker></mat-date-range-picker>
</mat-form-field>

Within the tags, we include two HTML <input> tags for user input of the start and dates. Each input element has two events, (dateInput) and (dateChange), which are bound to an event that receives the from or end date that is changed within the picker control.

dateRangeChanged(event: MatDatepickerInputEvent<Date>)
{
    … 
}

The HTML template also has a <mat-date-picker-toggle> tag that allows the date picker to display or hide.

In the hidden state, when the control is initially displayed, the picker control looks like this:

When the user clicks on the date icon to the right of the control, the picker displays and looks like this:

An additional HTML tag <mat-date-range-picker> can be used to template the date picker component into a variable that can be accessed from within the component source.

To be able to use the component input dates, we will need at least two variables to store the date selections within the parent component:

startDate: Date = new Date();
endDate: Date = new Date();

In the next section, I will show how to detect date range changes, then use the starting and ending dates to help us filter dates within an array of records that is added to a grid.

Detecting Date Range Changes

When a date selection changes, an event handler, dateRangeChanged() is used to process the selected date:

dateRangeChanged(event: MatDatepickerInputEvent<Date>)
{
    if (event.target.constructor.name == "MatStartDate")
    {
        this.startDate = event.value;
    }
    if (event.target.constructor.name == "MatEndDate")
    {
        this.endDate = event.value;
    }
    if (this.startDate && this.endDate)
    {
        console.log("Date range changed. date start = " + 
        this.startDate + ". end date = " + this.endDate);
        this.applyDateFilter();   
    } 
}

The event input parameter is of type MatDatepickerInputEvent<Date>. This parameter will be returned from either the picker’s start date control (MatStartDate), or from the picker’s end date control (MatEndDate). When both start and end dates are selected, they can be processed within the parent control. In the example I created, I have applied the selected dates to filtering Book Loan data’s dateLoaned field as shown below.

import { Book } from "./Book";

export class LoanView
{
    public id: number;
    public loanedBy: string;
    public dateLoaned: Date;
    public dateDue: Date;
    public dateReturn: Date; 
    public onShelf: boolean;
    public bookID: number;
    public book: Book;
    public returnMethod: string;
}

I will need two arrays to store the Loan record data and also an array to store the filtered loan data:

loans: LoanView[];
filteredLoans: LoanView[];

When the Loan data is loaded into the parent control during component initialisation, I assign the subscribed data into the above controls, with an additional property dateLoanedVal, a JavaScript date injected into each of the Loan objects within the loans array. The dateLoaned and dateReturn properties within the LoanView structure as JSON dates, so to compare these within a filter I will need to convert them to JavaScript dates. This is shown below using the RxJS map() operator: 

this.subscription = this.api.getBookLoans(this.id)
    .subscribe((res: LoanView[]) => {
        this.loans = res.map(m => 
        {
            var dateLoanedStr = m.dateLoaned;
            m['dateLoanedVal'] = new Date(dateLoanedStr);
            var dateReturnStr = m.dateReturn;
            m['dateReturnVal'] = new Date(dateReturnStr);
            return m;
       	});
this.filteredLoans = this.loans;

When the first date is selected within the picker, the control highlights the selected date as shown:

And when the second date is selected, that too is highlighted as shown:

When both dates have been selected, the date picker dropdown is hidden, and the selected dates are show in the edit controls as shown:

When the date selections have both been triggered, the applyDateFilter() method clears the filteredLoans array, loops through the loans array an checks if the dateLoanedVal property field lies between the selected dates from the date picker. If the dates are between these dates, then they are added to the filteredLoans array as shown: 

applyDateFilter()
{
    this.filteredLoans = [];
    this.loans.forEach(l => 
    {
        if ((l['dateLoanedVal'] >= this.startDate) && 
            (l['dateLoanedVal'] <= this.endDate))
            this.filteredLoans.push(l);
    });
	
    this.hasSearchResults$.next(this.filteredLoans.length > 0);
}

The hasSearchResults$ asynchronous observable is then set to display the results of the filtered data, which is shown below:

I have not formatted the dates nicely in the above results however you can get the idea behind using the Material date picker component. It allows you to restrict a particular date range and then use this range for additional user interface record filtering or for report parameters.

In addition, the date picker control looks quite stylish and would be useful in any Angular user interface. In addition, it is quite straightforward to use, and could be extended even further as part of a more elaborate control as part of a record filter or as part of as parameter within a report component.

That is all for today’s post.

I hope you have found this post useful and informative.

Social media & sharing icons powered by UltimatelySocial