Skip to content

Commit 3c69895

Browse files
authored
docs(datepicker): add docs and live example for date range picker (#19170)
Sets up some live examples and adds docs for the date range picker.
1 parent 96f968e commit 3c69895

18 files changed

+253
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.example-form-field {
2+
margin: 0 8px 16px 0;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<mat-form-field class="example-form-field">
2+
<mat-label>First campaign</mat-label>
3+
<mat-date-range-input
4+
[formGroup]="campaignOne"
5+
[rangePicker]="campaignOnePicker"
6+
[comparisonStart]="campaignTwo.value.start"
7+
[comparisonEnd]="campaignTwo.value.end">
8+
<input matStartDate matInput placeholder="Start date" formControlName="start">
9+
<input matEndDate matInput placeholder="End date" formControlName="end">
10+
</mat-date-range-input>
11+
<mat-datepicker-toggle matSuffix [for]="campaignOnePicker"></mat-datepicker-toggle>
12+
<mat-date-range-picker #campaignOnePicker></mat-date-range-picker>
13+
</mat-form-field>
14+
15+
<mat-form-field class="example-form-field">
16+
<mat-label>Second campaign</mat-label>
17+
<mat-date-range-input
18+
[formGroup]="campaignTwo"
19+
[rangePicker]="campaignTwoPicker"
20+
[comparisonStart]="campaignOne.value.start"
21+
[comparisonEnd]="campaignOne.value.end">
22+
<input matStartDate matInput placeholder="Start date" formControlName="start">
23+
<input matEndDate matInput placeholder="End date" formControlName="end">
24+
</mat-date-range-input>
25+
<mat-datepicker-toggle matSuffix [for]="campaignTwoPicker"></mat-datepicker-toggle>
26+
<mat-date-range-picker #campaignTwoPicker></mat-date-range-picker>
27+
</mat-form-field>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import {Component} from '@angular/core';
2+
import {FormGroup, FormControl} from '@angular/forms';
3+
4+
/** @title Date range picker comparison ranges */
5+
@Component({
6+
selector: 'date-range-picker-comparison-example',
7+
templateUrl: 'date-range-picker-comparison-example.html',
8+
styleUrls: ['date-range-picker-comparison-example.css'],
9+
})
10+
export class DateRangePickerComparisonExample {
11+
campaignOne: FormGroup;
12+
campaignTwo: FormGroup;
13+
14+
constructor() {
15+
const today = new Date();
16+
const month = today.getMonth();
17+
const year = today.getFullYear();
18+
19+
this.campaignOne = new FormGroup({
20+
start: new FormControl(new Date(year, month, 13)),
21+
end: new FormControl(new Date(year, month, 16))
22+
});
23+
24+
this.campaignTwo = new FormGroup({
25+
start: new FormControl(new Date(year, month, 15)),
26+
end: new FormControl(new Date(year, month, 19))
27+
});
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/** No CSS for this example */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<mat-form-field>
2+
<mat-label>Enter a date range</mat-label>
3+
<mat-date-range-input [formGroup]="range" [rangePicker]="picker">
4+
<input matStartDate matInput formControlName="start" placeholder="Start date">
5+
<input matEndDate matInput formControlName="end" placeholder="End date">
6+
</mat-date-range-input>
7+
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
8+
<mat-date-range-picker #picker></mat-date-range-picker>
9+
10+
<mat-error *ngIf="range.controls.start.hasError('matStartDateInvalid')">Invalid start date</mat-error>
11+
<mat-error *ngIf="range.controls.end.hasError('matEndDateInvalid')">Invalid end date</mat-error>
12+
</mat-form-field>
13+
14+
<p>Selected range: {{range.value | json}}</p>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {Component} from '@angular/core';
2+
import {FormGroup, FormControl} from '@angular/forms';
3+
4+
/** @title Date range picker forms integration */
5+
@Component({
6+
selector: 'date-range-picker-forms-example',
7+
templateUrl: 'date-range-picker-forms-example.html',
8+
styleUrls: ['date-range-picker-forms-example.css'],
9+
})
10+
export class DateRangePickerFormsExample {
11+
range = new FormGroup({
12+
start: new FormControl(),
13+
end: new FormControl()
14+
});
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/** No CSS for this example */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<mat-form-field>
2+
<mat-label>Enter a date range</mat-label>
3+
<mat-date-range-input [rangePicker]="picker">
4+
<input matStartDate matInput placeholder="Start date">
5+
<input matEndDate matInput placeholder="End date">
6+
</mat-date-range-input>
7+
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
8+
<mat-date-range-picker #picker></mat-date-range-picker>
9+
</mat-form-field>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {Component} from '@angular/core';
2+
3+
/** @title Basic date range picker */
4+
@Component({
5+
selector: 'date-range-picker-overview-example',
6+
templateUrl: 'date-range-picker-overview-example.html',
7+
styleUrls: ['date-range-picker-overview-example.css'],
8+
})
9+
export class DateRangePickerOverviewExample {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/** No CSS for this example */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<mat-form-field>
2+
<mat-label>Enter a date range</mat-label>
3+
<mat-date-range-input [rangePicker]="picker">
4+
<input matStartDate matInput placeholder="Start date">
5+
<input matEndDate matInput placeholder="End date">
6+
</mat-date-range-input>
7+
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
8+
<mat-date-range-picker #picker></mat-date-range-picker>
9+
</mat-form-field>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {Component, Injectable} from '@angular/core';
2+
import {DateAdapter} from '@angular/material/core';
3+
import {
4+
MatDateRangeSelectionStrategy,
5+
DateRange,
6+
MAT_DATE_RANGE_SELECTION_STRATEGY,
7+
} from '@angular/material/datepicker';
8+
9+
@Injectable()
10+
export class FiveDayRangeSelectionStrategy<D> implements MatDateRangeSelectionStrategy<D> {
11+
constructor(private _dateAdapter: DateAdapter<D>) {}
12+
13+
selectionFinished(date: D | null): DateRange<D> {
14+
return this._createFiveDayRange(date);
15+
}
16+
17+
createPreview(activeDate: D | null): DateRange<D> {
18+
return this._createFiveDayRange(activeDate);
19+
}
20+
21+
private _createFiveDayRange(date: D | null): DateRange<D> {
22+
if (date) {
23+
const start = this._dateAdapter.addCalendarDays(date, -2);
24+
const end = this._dateAdapter.addCalendarDays(date, 2);
25+
return new DateRange<D>(start, end);
26+
}
27+
28+
return new DateRange<D>(null, null);
29+
}
30+
}
31+
32+
/** @title Date range picker with custom a selection strategy */
33+
@Component({
34+
selector: 'date-range-picker-selection-strategy-example',
35+
templateUrl: 'date-range-picker-selection-strategy-example.html',
36+
styleUrls: ['date-range-picker-selection-strategy-example.css'],
37+
providers: [{
38+
provide: MAT_DATE_RANGE_SELECTION_STRATEGY,
39+
useClass: FiveDayRangeSelectionStrategy
40+
}]
41+
})
42+
export class DateRangePickerSelectionStrategyExample {}

src/components-examples/material/datepicker/index.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {CommonModule} from '@angular/common';
22
import {NgModule} from '@angular/core';
3-
import {ReactiveFormsModule} from '@angular/forms';
3+
import {ReactiveFormsModule, FormsModule} from '@angular/forms';
44
import {MatButtonModule} from '@angular/material/button';
55
import {MatNativeDateModule} from '@angular/material/core';
66
import {MatDatepickerModule} from '@angular/material/datepicker';
@@ -29,6 +29,18 @@ import {DatepickerValueExample} from './datepicker-value/datepicker-value-exampl
2929
import {
3030
DatepickerViewsSelectionExample
3131
} from './datepicker-views-selection/datepicker-views-selection-example';
32+
import {
33+
DateRangePickerOverviewExample
34+
} from './date-range-picker-overview/date-range-picker-overview-example';
35+
import {
36+
DateRangePickerFormsExample
37+
} from './date-range-picker-forms/date-range-picker-forms-example';
38+
import {
39+
DateRangePickerComparisonExample
40+
} from './date-range-picker-comparison/date-range-picker-comparison-example';
41+
import {
42+
DateRangePickerSelectionStrategyExample
43+
} from './date-range-picker-selection-strategy/date-range-picker-selection-strategy-example';
3244

3345
export {
3446
DatepickerApiExample,
@@ -48,6 +60,10 @@ export {
4860
DatepickerTouchExample,
4961
DatepickerValueExample,
5062
DatepickerViewsSelectionExample,
63+
DateRangePickerOverviewExample,
64+
DateRangePickerFormsExample,
65+
DateRangePickerComparisonExample,
66+
DateRangePickerSelectionStrategyExample,
5167
ExampleHeader,
5268
};
5369

@@ -69,6 +85,10 @@ const EXAMPLES = [
6985
DatepickerTouchExample,
7086
DatepickerValueExample,
7187
DatepickerViewsSelectionExample,
88+
DateRangePickerOverviewExample,
89+
DateRangePickerFormsExample,
90+
DateRangePickerComparisonExample,
91+
DateRangePickerSelectionStrategyExample,
7292
ExampleHeader,
7393
];
7494

@@ -81,6 +101,7 @@ const EXAMPLES = [
81101
MatIconModule,
82102
MatNativeDateModule,
83103
ReactiveFormsModule,
104+
FormsModule,
84105
],
85106
declarations: EXAMPLES,
86107
exports: EXAMPLES,

src/dev-app/datepicker/datepicker-demo.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ mat-calendar {
99
}
1010

1111
.demo-custom-range {
12-
@include mat-datepicker-range-colors(hotpink, teal, yellow, purple);
12+
@include mat-date-range-colors(hotpink, teal, yellow, purple);
1313
}

src/material/datepicker/_datepicker-theme.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ $mat-calendar-body-font-size: 13px !default;
1212
$mat-calendar-weekday-table-font-size: 11px !default;
1313

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

1818
.mat-calendar-body-selected {
@@ -181,7 +181,7 @@ $mat-calendar-weekday-table-font-size: 11px !default;
181181
}
182182
}
183183

184-
@mixin mat-datepicker-range-colors(
184+
@mixin mat-date-range-colors(
185185
$range-color,
186186
$comparison-color: rgba(#f9ab00, $mat-datepicker-range-fade-amount),
187187
$overlap-color: #a8dab5,

src/material/datepicker/date-range-input.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ import {DateRange, MatDateSelectionModel} from './date-selection-model';
3838

3939
let nextUniqueId = 0;
4040

41-
// TODO(crisbeto): when adding live examples, should how to use with `FormGroup`.
42-
4341
@Component({
4442
selector: 'mat-date-range-input',
4543
templateUrl: 'date-range-input.html',

src/material/datepicker/date-range-selection-strategy.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import {Injectable, InjectionToken} from '@angular/core';
1010
import {DateAdapter} from '@angular/material/core';
1111
import {DateRange} from './date-selection-model';
1212

13-
// TODO(crisbeto): this needs to be expanded to allow for the preview range to be customized.
14-
1513
/** Injection token used to customize the date range selection behavior. */
1614
export const MAT_DATE_RANGE_SELECTION_STRATEGY =
1715
new InjectionToken<MatDateRangeSelectionStrategy<any>>('MAT_DATE_RANGE_SELECTION_STRATEGY');

src/material/datepicker/datepicker.md

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ An optional datepicker toggle button is available. A toggle can be added to the
2222
```
2323

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

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

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

40+
### Date range selection
41+
42+
If you want your users to select a range of dates, instead of a single date, you can use the
43+
`mat-date-range-input` and `mat-date-range-picker` components. They work in similarly to the
44+
`mat-datepicker` and the basic datepicker input.
45+
46+
The `mat-date-range-input` component requires two `input` elements for the start and end dates,
47+
respectively:
48+
49+
```html
50+
<mat-date-range-input>
51+
<input matStartDate matInput placeholder="Start date">
52+
<input matEndDate matInput placeholder="End date">
53+
</mat-date-range-input>
54+
```
55+
56+
The `mat-date-range-picker` component acts the the pop-up panel for selecting dates. This works in
57+
the same way as `mat-datepicker`, but allows the user to select multiple times:
58+
59+
```html
60+
<mat-date-range-picker #picker></mat-date-range-picker>
61+
```
62+
63+
Connect the range picker and range input using the `rangePicker` property:
64+
65+
```html
66+
<mat-date-range-input [rangePicker]="picker">
67+
<input matStartDate matInput placeholder="Start date">
68+
<input matEndDate matInput placeholder="End date">
69+
</mat-date-range-input>
70+
71+
<mat-date-range-picker #picker></mat-date-range-picker>
72+
```
73+
74+
<!-- example(date-range-picker-overview) -->
75+
76+
### Date range input forms integration
77+
78+
The `mat-date-range-input` component can be used together with the `FormGroup` directive from
79+
`@angular/forms` to group the start and end values together and to validate them as a group.
80+
81+
<!-- example(date-range-picker-forms) -->
82+
4083
### Setting the calendar starting view
4184

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

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

208+
### Comparison ranges
209+
210+
If your users need to compare the date range that they're currently selecting with another range,
211+
you can provide the comparison range start and end dates to the `mat-date-range-input` using the
212+
`comparisonStart` and `comparisonEnd` bindings. The comparison range will be rendered statically
213+
within the calendar, but it will change colors to indicate which dates overlap with the user's
214+
selected range.
215+
216+
<!-- example(date-range-picker-comparison) -->
217+
218+
Note that comparison and overlap colors aren't derived from the current theme, due
219+
to limitations in the Material Design theming system. They can be customized using the
220+
`mat-date-range-colors` mixin.
221+
222+
### Customizing the date selection logic
223+
224+
The `mat-date-range-picker` supports custom behaviors for range previews and selection. To customize
225+
this, you first create a class that implements `MatDateRangeSelectionStrategy`, and then provide
226+
the class via the `MAT_DATE_RANGE_SELECTION_STRATEGY` injection token. The following example
227+
uses the range selection strategy to create a custom range picker that limits the user to five-day
228+
ranges.
229+
230+
<!-- example(date-range-picker-selection-strategy) -->
231+
165232
### Touch UI mode
166233

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

0 commit comments

Comments
 (0)