Skip to content

docs(datepicker): add docs and live examples for date range picker #19170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.example-form-field {
margin: 0 8px 16px 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<mat-form-field class="example-form-field">
<mat-label>First campaign</mat-label>
<mat-date-range-input
[formGroup]="campaignOne"
[rangePicker]="campaignOnePicker"
[comparisonStart]="campaignTwo.value.start"
[comparisonEnd]="campaignTwo.value.end">
<input matStartDate matInput placeholder="Start date" formControlName="start">
<input matEndDate matInput placeholder="End date" formControlName="end">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="campaignOnePicker"></mat-datepicker-toggle>
<mat-date-range-picker #campaignOnePicker></mat-date-range-picker>
</mat-form-field>

<mat-form-field class="example-form-field">
<mat-label>Second campaign</mat-label>
<mat-date-range-input
[formGroup]="campaignTwo"
[rangePicker]="campaignTwoPicker"
[comparisonStart]="campaignOne.value.start"
[comparisonEnd]="campaignOne.value.end">
<input matStartDate matInput placeholder="Start date" formControlName="start">
<input matEndDate matInput placeholder="End date" formControlName="end">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="campaignTwoPicker"></mat-datepicker-toggle>
<mat-date-range-picker #campaignTwoPicker></mat-date-range-picker>
</mat-form-field>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {Component} from '@angular/core';
import {FormGroup, FormControl} from '@angular/forms';

/** @title Date range picker comparison ranges */
@Component({
selector: 'date-range-picker-comparison-example',
templateUrl: 'date-range-picker-comparison-example.html',
styleUrls: ['date-range-picker-comparison-example.css'],
})
export class DateRangePickerComparisonExample {
campaignOne: FormGroup;
campaignTwo: FormGroup;

constructor() {
const today = new Date();
const month = today.getMonth();
const year = today.getFullYear();

this.campaignOne = new FormGroup({
start: new FormControl(new Date(year, month, 13)),
end: new FormControl(new Date(year, month, 16))
});

this.campaignTwo = new FormGroup({
start: new FormControl(new Date(year, month, 15)),
end: new FormControl(new Date(year, month, 19))
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** No CSS for this example */
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<mat-form-field>
<mat-label>Enter a date range</mat-label>
<mat-date-range-input [formGroup]="range" [rangePicker]="picker">
<input matStartDate matInput formControlName="start" placeholder="Start date">
<input matEndDate matInput formControlName="end" placeholder="End date">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>

<mat-error *ngIf="range.controls.start.hasError('matStartDateInvalid')">Invalid start date</mat-error>
<mat-error *ngIf="range.controls.end.hasError('matEndDateInvalid')">Invalid end date</mat-error>
</mat-form-field>

<p>Selected range: {{range.value | json}}</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {FormGroup, FormControl} from '@angular/forms';

/** @title Date range picker forms integration */
@Component({
selector: 'date-range-picker-forms-example',
templateUrl: 'date-range-picker-forms-example.html',
styleUrls: ['date-range-picker-forms-example.css'],
})
export class DateRangePickerFormsExample {
range = new FormGroup({
start: new FormControl(),
end: new FormControl()
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** No CSS for this example */
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<mat-form-field>
<mat-label>Enter a date range</mat-label>
<mat-date-range-input [rangePicker]="picker">
<input matStartDate matInput placeholder="Start date">
<input matEndDate matInput placeholder="End date">
</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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {Component} from '@angular/core';

/** @title Basic date range picker */
@Component({
selector: 'date-range-picker-overview-example',
templateUrl: 'date-range-picker-overview-example.html',
styleUrls: ['date-range-picker-overview-example.css'],
})
export class DateRangePickerOverviewExample {}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** No CSS for this example */
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<mat-form-field>
<mat-label>Enter a date range</mat-label>
<mat-date-range-input [rangePicker]="picker">
<input matStartDate matInput placeholder="Start date">
<input matEndDate matInput placeholder="End date">
</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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {Component, Injectable} from '@angular/core';
import {DateAdapter} from '@angular/material/core';
import {
MatDateRangeSelectionStrategy,
DateRange,
MAT_DATE_RANGE_SELECTION_STRATEGY,
} from '@angular/material/datepicker';

@Injectable()
export class FiveDayRangeSelectionStrategy<D> implements MatDateRangeSelectionStrategy<D> {
constructor(private _dateAdapter: DateAdapter<D>) {}

selectionFinished(date: D | null): DateRange<D> {
return this._createFiveDayRange(date);
}

createPreview(activeDate: D | null): DateRange<D> {
return this._createFiveDayRange(activeDate);
}

private _createFiveDayRange(date: D | null): DateRange<D> {
if (date) {
const start = this._dateAdapter.addCalendarDays(date, -2);
const end = this._dateAdapter.addCalendarDays(date, 2);
return new DateRange<D>(start, end);
}

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

/** @title Date range picker with custom a selection strategy */
@Component({
selector: 'date-range-picker-selection-strategy-example',
templateUrl: 'date-range-picker-selection-strategy-example.html',
styleUrls: ['date-range-picker-selection-strategy-example.css'],
providers: [{
provide: MAT_DATE_RANGE_SELECTION_STRATEGY,
useClass: FiveDayRangeSelectionStrategy
}]
})
export class DateRangePickerSelectionStrategyExample {}
23 changes: 22 additions & 1 deletion src/components-examples/material/datepicker/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {ReactiveFormsModule} from '@angular/forms';
import {ReactiveFormsModule, FormsModule} from '@angular/forms';
import {MatButtonModule} from '@angular/material/button';
import {MatNativeDateModule} from '@angular/material/core';
import {MatDatepickerModule} from '@angular/material/datepicker';
Expand Down Expand Up @@ -29,6 +29,18 @@ import {DatepickerValueExample} from './datepicker-value/datepicker-value-exampl
import {
DatepickerViewsSelectionExample
} from './datepicker-views-selection/datepicker-views-selection-example';
import {
DateRangePickerOverviewExample
} from './date-range-picker-overview/date-range-picker-overview-example';
import {
DateRangePickerFormsExample
} from './date-range-picker-forms/date-range-picker-forms-example';
import {
DateRangePickerComparisonExample
} from './date-range-picker-comparison/date-range-picker-comparison-example';
import {
DateRangePickerSelectionStrategyExample
} from './date-range-picker-selection-strategy/date-range-picker-selection-strategy-example';

export {
DatepickerApiExample,
Expand All @@ -48,6 +60,10 @@ export {
DatepickerTouchExample,
DatepickerValueExample,
DatepickerViewsSelectionExample,
DateRangePickerOverviewExample,
DateRangePickerFormsExample,
DateRangePickerComparisonExample,
DateRangePickerSelectionStrategyExample,
ExampleHeader,
};

Expand All @@ -69,6 +85,10 @@ const EXAMPLES = [
DatepickerTouchExample,
DatepickerValueExample,
DatepickerViewsSelectionExample,
DateRangePickerOverviewExample,
DateRangePickerFormsExample,
DateRangePickerComparisonExample,
DateRangePickerSelectionStrategyExample,
ExampleHeader,
];

Expand All @@ -81,6 +101,7 @@ const EXAMPLES = [
MatIconModule,
MatNativeDateModule,
ReactiveFormsModule,
FormsModule,
],
declarations: EXAMPLES,
exports: EXAMPLES,
Expand Down
2 changes: 1 addition & 1 deletion src/dev-app/datepicker/datepicker-demo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ mat-calendar {
}

.demo-custom-range {
@include mat-datepicker-range-colors(hotpink, teal, yellow, purple);
@include mat-date-range-colors(hotpink, teal, yellow, purple);
}
4 changes: 2 additions & 2 deletions src/material/datepicker/_datepicker-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ $mat-calendar-body-font-size: 13px !default;
$mat-calendar-weekday-table-font-size: 11px !default;

@mixin _mat-datepicker-color($palette) {
@include mat-datepicker-range-colors(
@include mat-date-range-colors(
mat-color($palette, default, $mat-datepicker-range-fade-amount));

.mat-calendar-body-selected {
Expand Down Expand Up @@ -181,7 +181,7 @@ $mat-calendar-weekday-table-font-size: 11px !default;
}
}

@mixin mat-datepicker-range-colors(
@mixin mat-date-range-colors(
$range-color,
$comparison-color: rgba(#f9ab00, $mat-datepicker-range-fade-amount),
$overlap-color: #a8dab5,
Expand Down
2 changes: 0 additions & 2 deletions src/material/datepicker/date-range-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ import {DateRange, MatDateSelectionModel} from './date-selection-model';

let nextUniqueId = 0;

// TODO(crisbeto): when adding live examples, should how to use with `FormGroup`.

@Component({
selector: 'mat-date-range-input',
templateUrl: 'date-range-input.html',
Expand Down
2 changes: 0 additions & 2 deletions src/material/datepicker/date-range-selection-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import {Injectable, InjectionToken} from '@angular/core';
import {DateAdapter} from '@angular/material/core';
import {DateRange} from './date-selection-model';

// TODO(crisbeto): this needs to be expanded to allow for the preview range to be customized.

/** Injection token used to customize the date range selection behavior. */
export const MAT_DATE_RANGE_SELECTION_STRATEGY =
new InjectionToken<MatDateRangeSelectionStrategy<any>>('MAT_DATE_RANGE_SELECTION_STRATEGY');
Expand Down
69 changes: 68 additions & 1 deletion src/material/datepicker/datepicker.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ An optional datepicker toggle button is available. A toggle can be added to the
```

This works exactly the same with an input that is part of an `<mat-form-field>` and the toggle
can easily be used as a prefix or suffix on the material input:
can easily be used as a prefix or suffix on the Material input:

```html
<mat-form-field>
Expand All @@ -37,6 +37,49 @@ by using the `matDatepickerToggleIcon` directive:

<!-- example(datepicker-custom-icon) -->

### Date range selection

If you want your users to select a range of dates, instead of a single date, you can use the
`mat-date-range-input` and `mat-date-range-picker` components. They work in similarly to the
`mat-datepicker` and the basic datepicker input.

The `mat-date-range-input` component requires two `input` elements for the start and end dates,
respectively:

```html
<mat-date-range-input>
<input matStartDate matInput placeholder="Start date">
<input matEndDate matInput placeholder="End date">
</mat-date-range-input>
```

The `mat-date-range-picker` component acts the the pop-up panel for selecting dates. This works in
the same way as `mat-datepicker`, but allows the user to select multiple times:

```html
<mat-date-range-picker #picker></mat-date-range-picker>
```

Connect the range picker and range input using the `rangePicker` property:

```html
<mat-date-range-input [rangePicker]="picker">
<input matStartDate matInput placeholder="Start date">
<input matEndDate matInput placeholder="End date">
</mat-date-range-input>

<mat-date-range-picker #picker></mat-date-range-picker>
```

<!-- example(date-range-picker-overview) -->

### Date range input forms integration

The `mat-date-range-input` component can be used together with the `FormGroup` directive from
`@angular/forms` to group the start and end values together and to validate them as a group.

<!-- example(date-range-picker-forms) -->

### Setting the calendar starting view

The `startView` property of `<mat-datepicker>` can be used to set the view that will show up when
Expand Down Expand Up @@ -162,6 +205,30 @@ but allow selection via the calendar or vice-versa.

<!-- example(datepicker-disabled) -->

### Comparison ranges

If your users need to compare the date range that they're currently selecting with another range,
you can provide the comparison range start and end dates to the `mat-date-range-input` using the
`comparisonStart` and `comparisonEnd` bindings. The comparison range will be rendered statically
within the calendar, but it will change colors to indicate which dates overlap with the user's
selected range.

<!-- example(date-range-picker-comparison) -->

Note that comparison and overlap colors aren't derived from the current theme, due
to limitations in the Material Design theming system. They can be customized using the
`mat-date-range-colors` mixin.

### Customizing the date selection logic

The `mat-date-range-picker` supports custom behaviors for range previews and selection. To customize
this, you first create a class that implements `MatDateRangeSelectionStrategy`, and then provide
the class via the `MAT_DATE_RANGE_SELECTION_STRATEGY` injection token. The following example
uses the range selection strategy to create a custom range picker that limits the user to five-day
ranges.

<!-- example(date-range-picker-selection-strategy) -->

### Touch UI mode

The datepicker normally opens as a popup under the input. However this is not ideal for touch
Expand Down