Skip to content

Commit c40a0fd

Browse files
xlou978mmalerba
authored andcommitted
Adds a date selection model (#17363)
* Adds a date selection model * Adds a date selection model
1 parent 8e141ef commit c40a0fd

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {DateAdapter} from '@angular/material/core';
10+
import {Subject, Observable} from 'rxjs';
11+
12+
export abstract class MatDateSelectionModel<D> {
13+
protected _valueChangesSubject = new Subject<void>();
14+
valueChanges: Observable<void> = this._valueChangesSubject.asObservable();
15+
16+
constructor(protected readonly adapter: DateAdapter<D>) {}
17+
18+
destroy() {
19+
this._valueChangesSubject.complete();
20+
}
21+
22+
abstract add(date: D | null): void;
23+
abstract isComplete(): boolean;
24+
abstract isSame(other: MatDateSelectionModel<D>): boolean;
25+
abstract isValid(): boolean;
26+
}
27+
28+
export interface DateRange<D> {
29+
start: D | null;
30+
end: D | null;
31+
}
32+
33+
/**
34+
* Concrete implementation of a MatDateSelectionModel that holds a single date.
35+
*/
36+
export class MatSingleDateSelectionModel<D> extends MatDateSelectionModel<D> {
37+
private _date: D | null = null;
38+
39+
constructor(adapter: DateAdapter<D>, date?: D | null) {
40+
super(adapter);
41+
this._date = date === undefined ? null : date;
42+
}
43+
44+
add(date: D | null) {
45+
this._date = date;
46+
this._valueChangesSubject.next();
47+
}
48+
49+
compareDate(other: MatSingleDateSelectionModel<D>) {
50+
const date = this.asDate();
51+
const otherDate = other.asDate();
52+
if (date != null && otherDate != null) {
53+
return this.adapter.compareDate(date, otherDate);
54+
}
55+
return date === otherDate;
56+
}
57+
58+
isComplete() { return this._date != null; }
59+
60+
isSame(other: MatDateSelectionModel<D>): boolean {
61+
return other instanceof MatSingleDateSelectionModel &&
62+
this.adapter.sameDate(other.asDate(), this._date);
63+
}
64+
65+
isValid(): boolean {
66+
return this._date != null && this.adapter.isDateInstance(this._date) &&
67+
this.adapter.isValid(this._date);
68+
}
69+
70+
asDate(): D | null {
71+
return this.isValid() ? this._date : null;
72+
}
73+
}
74+
75+
/**
76+
* Concrete implementation of a MatDateSelectionModel that holds a date range, represented by
77+
* a start date and an end date.
78+
*/
79+
export class MatRangeDateSelectionModel<D> extends MatDateSelectionModel<D> {
80+
private _start: D | null = null;
81+
private _end: D | null = null;
82+
83+
constructor(adapter: DateAdapter<D>, start?: D | null, end?: D | null) {
84+
super(adapter);
85+
this._start = start === undefined ? null : start;
86+
this._end = end === undefined ? null : end;
87+
}
88+
89+
/**
90+
* Adds an additional date to the range. If no date is set thus far, it will set it to the
91+
* beginning. If the beginning is set, it will set it to the end.
92+
* If add is called on a complete selection, it will empty the selection and set it as the start.
93+
*/
94+
add(date: D | null): void {
95+
if (this._start == null) {
96+
this._start = date;
97+
} else if (this._end == null) {
98+
this._end = date;
99+
} else {
100+
this._start = date;
101+
this._end = null;
102+
}
103+
104+
this._valueChangesSubject.next();
105+
}
106+
107+
setRange(start: D | null, end: D | null) {
108+
this._start = start;
109+
this._end = end;
110+
}
111+
112+
isComplete(): boolean {
113+
return this._start != null && this._end != null;
114+
}
115+
116+
isSame(other: MatDateSelectionModel<D>): boolean {
117+
if (other instanceof MatRangeDateSelectionModel) {
118+
const otherRange = other.asRange();
119+
return this.adapter.sameDate(this._start, otherRange.start) &&
120+
this.adapter.sameDate(this._end, otherRange.end);
121+
}
122+
return false;
123+
}
124+
125+
isValid(): boolean {
126+
return this._start != null && this._end != null &&
127+
this.adapter.isValid(this._start!) && this.adapter.isValid(this._end!);
128+
}
129+
130+
asRange(): DateRange<D> {
131+
return {
132+
start: this._start,
133+
end: this._end,
134+
};
135+
}
136+
}

src/material/core/datetime/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export * from './date-adapter';
1717
export * from './date-formats';
1818
export * from './native-date-adapter';
1919
export * from './native-date-formats';
20+
export * from './date-selection-model';
2021

2122

2223
@NgModule({

tools/public_api_guard/material/core.d.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ export declare abstract class DateAdapter<D> {
7979
abstract today(): D;
8080
}
8181

82+
export interface DateRange<D> {
83+
end: D | null;
84+
start: D | null;
85+
}
86+
8287
export declare const JAN = 0, FEB = 1, MAR = 2, APR = 3, MAY = 4, JUN = 5, JUL = 6, AUG = 7, SEP = 8, OCT = 9, NOV = 10, DEC = 11;
8388

8489
export declare const defaultRippleAnimationConfig: {
@@ -213,6 +218,18 @@ export declare type MatDateFormats = {
213218
};
214219
};
215220

221+
export declare abstract class MatDateSelectionModel<D> {
222+
protected _valueChangesSubject: Subject<void>;
223+
protected readonly adapter: DateAdapter<D>;
224+
valueChanges: Observable<void>;
225+
constructor(adapter: DateAdapter<D>);
226+
abstract add(date: D | null): void;
227+
destroy(): void;
228+
abstract isComplete(): boolean;
229+
abstract isSame(other: MatDateSelectionModel<D>): boolean;
230+
abstract isValid(): boolean;
231+
}
232+
216233
export declare const MATERIAL_SANITY_CHECKS: InjectionToken<SanityChecks>;
217234

218235
export declare class MatLine {
@@ -289,6 +306,16 @@ export declare class MatPseudoCheckboxModule {
289306

290307
export declare type MatPseudoCheckboxState = 'unchecked' | 'checked' | 'indeterminate';
291308

309+
export declare class MatRangeDateSelectionModel<D> extends MatDateSelectionModel<D> {
310+
constructor(adapter: DateAdapter<D>, start?: D | null, end?: D | null);
311+
add(date: D | null): void;
312+
asRange(): DateRange<D>;
313+
isComplete(): boolean;
314+
isSame(other: MatDateSelectionModel<D>): boolean;
315+
isValid(): boolean;
316+
setRange(start: D | null, end: D | null): void;
317+
}
318+
292319
export declare class MatRipple implements OnInit, OnDestroy, RippleTarget {
293320
animation: RippleAnimationConfig;
294321
centered: boolean;
@@ -310,6 +337,16 @@ export declare class MatRipple implements OnInit, OnDestroy, RippleTarget {
310337
export declare class MatRippleModule {
311338
}
312339

340+
export declare class MatSingleDateSelectionModel<D> extends MatDateSelectionModel<D> {
341+
constructor(adapter: DateAdapter<D>, date?: D | null);
342+
add(date: D | null): void;
343+
asDate(): D | null;
344+
compareDate(other: MatSingleDateSelectionModel<D>): number | boolean;
345+
isComplete(): boolean;
346+
isSame(other: MatDateSelectionModel<D>): boolean;
347+
isValid(): boolean;
348+
}
349+
313350
export declare const JAN = 0, FEB = 1, MAR = 2, APR = 3, MAY = 4, JUN = 5, JUL = 6, AUG = 7, SEP = 8, OCT = 9, NOV = 10, DEC = 11;
314351

315352
export declare function mixinColor<T extends Constructor<HasElementRef>>(base: T, defaultColor?: ThemePalette): CanColorCtor & T;

0 commit comments

Comments
 (0)