diff --git a/src/demo-app/demo-app-module.ts b/src/demo-app/demo-app-module.ts index 596484081024..2cb925c4aacf 100644 --- a/src/demo-app/demo-app-module.ts +++ b/src/demo-app/demo-app-module.ts @@ -1,4 +1,4 @@ -import {NgModule, ApplicationRef} from '@angular/core'; +import {ApplicationRef, NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {HttpModule} from '@angular/http'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; @@ -6,14 +6,15 @@ import {RouterModule} from '@angular/router'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {DemoApp, Home} from './demo-app/demo-app'; import { - MaterialModule, - OverlayContainer, FullscreenOverlayContainer, + MaterialModule, + MdNativeDateModule, MdSelectionModule, + OverlayContainer } from '@angular/material'; import {DEMO_APP_ROUTES} from './demo-app/routes'; import {ProgressBarDemo} from './progress-bar/progress-bar-demo'; -import {JazzDialog, ContentElementDialog, DialogDemo, IFrameDialog} from './dialog/dialog-demo'; +import {ContentElementDialog, DialogDemo, IFrameDialog, JazzDialog} from './dialog/dialog-demo'; import {RippleDemo} from './ripple/ripple-demo'; import {IconDemo} from './icon/icon-demo'; import {GesturesDemo} from './gestures/gestures-demo'; @@ -27,18 +28,18 @@ import {ListDemo} from './list/list-demo'; import {BaselineDemo} from './baseline/baseline-demo'; import {GridListDemo} from './grid-list/grid-list-demo'; import {LiveAnnouncerDemo} from './live-announcer/live-announcer-demo'; -import {OverlayDemo, SpagettiPanel, RotiniPanel} from './overlay/overlay-demo'; +import {OverlayDemo, RotiniPanel, SpagettiPanel} from './overlay/overlay-demo'; import {SlideToggleDemo} from './slide-toggle/slide-toggle-demo'; import {ToolbarDemo} from './toolbar/toolbar-demo'; import {ButtonDemo} from './button/button-demo'; -import {MdCheckboxDemoNestedChecklist, CheckboxDemo} from './checkbox/checkbox-demo'; +import {CheckboxDemo, MdCheckboxDemoNestedChecklist} from './checkbox/checkbox-demo'; import {SelectDemo} from './select/select-demo'; import {SliderDemo} from './slider/slider-demo'; import {SidenavDemo} from './sidenav/sidenav-demo'; import {SnackBarDemo} from './snack-bar/snack-bar-demo'; import {PortalDemo, ScienceJoke} from './portal/portal-demo'; import {MenuDemo} from './menu/menu-demo'; -import {TabsDemo, SunnyTabContent, RainyTabContent, FoggyTabContent} from './tabs/tabs-demo'; +import {FoggyTabContent, RainyTabContent, SunnyTabContent, TabsDemo} from './tabs/tabs-demo'; import {PlatformDemo} from './platform/platform-demo'; import {AutocompleteDemo} from './autocomplete/autocomplete-demo'; import {InputDemo} from './input/input-demo'; @@ -55,6 +56,7 @@ import {DatepickerDemo} from './datepicker/datepicker-demo'; ReactiveFormsModule, RouterModule.forRoot(DEMO_APP_ROUTES), MaterialModule.forRoot(), + MdNativeDateModule, MdSelectionModule, ], declarations: [ diff --git a/src/lib/core/core.ts b/src/lib/core/core.ts index c4a2ffc2835a..e8a6676b0162 100644 --- a/src/lib/core/core.ts +++ b/src/lib/core/core.ts @@ -8,7 +8,6 @@ import {OverlayModule} from './overlay/overlay-directives'; import {A11yModule} from './a11y/index'; import {MdSelectionModule} from './selection/index'; import {MdRippleModule} from './ripple/index'; -import {DatetimeModule} from './datetime/index'; // RTL @@ -128,7 +127,6 @@ export * from './datetime/index'; A11yModule, MdOptionModule, MdSelectionModule, - DatetimeModule, ], exports: [ MdLineModule, @@ -140,7 +138,6 @@ export * from './datetime/index'; A11yModule, MdOptionModule, MdSelectionModule, - DatetimeModule, ], }) export class MdCoreModule { diff --git a/src/lib/core/datetime/date-adapter.ts b/src/lib/core/datetime/date-adapter.ts index c7d9d1274bf9..33148d3aa714 100644 --- a/src/lib/core/datetime/date-adapter.ts +++ b/src/lib/core/datetime/date-adapter.ts @@ -58,15 +58,6 @@ export abstract class DateAdapter { */ abstract getYearName(date: D): string; - /** - * Gets the name for the month and year of the given date. - * @param date The date to get the month and year name for. - * @param monthStyle The naming style for the month - * (e.g. long = 'January', short = 'Jan', narrow = 'J'). - * @returns The name of the month and year of the given date (e.g. 'Jan 2017'). - */ - abstract getMonthYearName(date: D, monthStyle: 'long' | 'short' | 'narrow'): string; - /** * Gets the first day of the week. * @returns The first day of the week (0-indexed, 0 = Sunday). @@ -80,13 +71,6 @@ export abstract class DateAdapter { */ abstract getNumDaysInMonth(date: D): number; - /** - * Gets a set of default formats to use for displaying the date in different contexts. - * @returns An object with the following default formats: - * - date: The default format for showing just the date without any time information. - */ - abstract getDefaultFormats(): {date: any}; - /** * Clones the given date. * @param date The date to clone @@ -113,18 +97,19 @@ export abstract class DateAdapter { /** * Parses a date from a value. * @param value The value to parse. - * @param fmt The expected format of the value being parsed (type is implementation-dependent). + * @param parseFormat The expected format of the value being parsed + * (type is implementation-dependent). * @returns The parsed date, or null if date could not be parsed. */ - abstract parse(value: any, fmt?: any): D | null; + abstract parse(value: any, parseFormat: any): D | null; /** * Formats a date as a string. * @param date The value to parse. - * @param fmt The format to use for the result string. + * @param displayFormat The format to use to display the date as a string. * @returns The parsed date, or null if date could not be parsed. */ - abstract format(date: D, fmt?: any): string; + abstract format(date: D, displayFormat: any): string; /** * Adds the given number of years to the date. Years are counted as if flipping 12 pages on the diff --git a/src/lib/core/datetime/date-formats.ts b/src/lib/core/datetime/date-formats.ts new file mode 100644 index 000000000000..3a93cb160f05 --- /dev/null +++ b/src/lib/core/datetime/date-formats.ts @@ -0,0 +1,15 @@ +import {InjectionToken} from '@angular/core'; + + +export type MdDateFormats = { + parse: { + dateInput: any + }, + display: { + dateInput: any, + monthYearLabel: any, + } +}; + + +export const MD_DATE_FORMATS = new InjectionToken('md-date-formats'); diff --git a/src/lib/core/datetime/index.ts b/src/lib/core/datetime/index.ts index 9dd521c46bd2..7228f0ca52fe 100644 --- a/src/lib/core/datetime/index.ts +++ b/src/lib/core/datetime/index.ts @@ -1,6 +1,8 @@ import {NgModule} from '@angular/core'; import {DateAdapter} from './date-adapter'; import {NativeDateAdapter} from './native-date-adapter'; +import {MD_DATE_FORMATS} from './date-formats'; +import {MD_NATIVE_DATE_FORMATS} from './native-date-formats'; export * from './date-adapter'; @@ -10,4 +12,11 @@ export * from './native-date-adapter'; @NgModule({ providers: [{provide: DateAdapter, useClass: NativeDateAdapter}], }) -export class DatetimeModule {} +export class NativeDateModule {} + + +@NgModule({ + imports: [NativeDateModule], + providers: [{provide: MD_DATE_FORMATS, useValue: MD_NATIVE_DATE_FORMATS}], +}) +export class MdNativeDateModule {} diff --git a/src/lib/core/datetime/native-date-adapter.spec.ts b/src/lib/core/datetime/native-date-adapter.spec.ts index 84b013b050e9..b7fd459e1138 100644 --- a/src/lib/core/datetime/native-date-adapter.spec.ts +++ b/src/lib/core/datetime/native-date-adapter.spec.ts @@ -104,32 +104,10 @@ describe('NativeDateAdapter', () => { expect(adapter.getYearName(new Date(2017, JAN, 1))).toBe('2017年'); }); - it('should get long month and year name', () => { - expect(adapter.getMonthYearName(new Date(2017, JAN, 1), 'long')).toBe('January 2017'); - }); - - it('should get short month and year name', () => { - expect(adapter.getMonthYearName(new Date(2017, JAN, 1), 'short')).toBe('Jan 2017'); - }); - - it('should get narrow month and year name', () => { - expect(adapter.getMonthYearName(new Date(2017, JAN, 1), 'narrow')).toBe('J 2017'); - }); - - it('should get month and year name in a different locale', () => { - adapter.setLocale('ja-JP'); - expect(adapter.getMonthYearName(new Date(2017, JAN, 1), 'long')).toBe('2017年1月'); - }); - it('should get first day of week', () => { expect(adapter.getFirstDayOfWeek()).toBe(0); }); - it('should get default formats', () => { - let dtf = new Intl.DateTimeFormat('en-US', adapter.getDefaultFormats().date); - expect(dtf.format(new Date(2017, 1, 1))).toEqual('2/1/2017'); - }); - it('should create Date', () => { expect(adapter.createDate(2017, JAN, 1)).toEqual(new Date(2017, JAN, 1)); }); diff --git a/src/lib/core/datetime/native-date-adapter.ts b/src/lib/core/datetime/native-date-adapter.ts index 57a7461f9e6c..7ea5c8e4efac 100644 --- a/src/lib/core/datetime/native-date-adapter.ts +++ b/src/lib/core/datetime/native-date-adapter.ts @@ -85,15 +85,6 @@ export class NativeDateAdapter extends DateAdapter { return String(this.getYear(date)); } - getMonthYearName(date: Date, monthStyle: 'long' | 'short' | 'narrow'): string { - if (SUPPORTS_INTL_API) { - let dtf = new Intl.DateTimeFormat(this.locale, {month: monthStyle, year: 'numeric'}); - return dtf.format(date); - } - let monthName = this.getMonthNames(monthStyle)[this.getMonth(date)]; - return `${monthName} ${this.getYear(date)}`; - } - getFirstDayOfWeek(): number { // We can't tell using native JS Date what the first day of the week is, we default to Sunday. return 0; @@ -104,16 +95,6 @@ export class NativeDateAdapter extends DateAdapter { this.getYear(date), this.getMonth(date) + 1, 0)); } - getDefaultFormats(): {date: Object} { - return { - date: { - year: 'numeric', - month: 'numeric', - day: 'numeric' - } - }; - } - clone(date: Date): Date { return this.createDate(this.getYear(date), this.getMonth(date), this.getDate(date)); } @@ -140,16 +121,16 @@ export class NativeDateAdapter extends DateAdapter { return new Date(); } - parse(value: any, fmt?: Object): Date | null { + parse(value: any, parseFormat: Object): Date | null { // We have no way using the native JS Date to set the parse format or locale, so we ignore these // parameters. let timestamp = typeof value == 'number' ? value : Date.parse(value); return isNaN(timestamp) ? null : new Date(timestamp); } - format(date: Date, fmt?: Object): string { + format(date: Date, displayFormat: Object): string { if (SUPPORTS_INTL_API) { - let dtf = new Intl.DateTimeFormat(this.locale, fmt); + let dtf = new Intl.DateTimeFormat(this.locale, displayFormat); return dtf.format(date); } return date.toDateString(); diff --git a/src/lib/core/datetime/native-date-formats.ts b/src/lib/core/datetime/native-date-formats.ts new file mode 100644 index 000000000000..5d20f3b03097 --- /dev/null +++ b/src/lib/core/datetime/native-date-formats.ts @@ -0,0 +1,12 @@ +import {MdDateFormats} from './date-formats'; + + +export const MD_NATIVE_DATE_FORMATS: MdDateFormats = { + parse: { + dateInput: null, + }, + display: { + dateInput: {year: 'numeric', month: 'numeric', day: 'numeric'}, + monthYearLabel: {year: 'numeric', month: 'short'}, + } +}; diff --git a/src/lib/datepicker/calendar.spec.ts b/src/lib/datepicker/calendar.spec.ts index 1faaeba88769..8fc00dba5978 100644 --- a/src/lib/datepicker/calendar.spec.ts +++ b/src/lib/datepicker/calendar.spec.ts @@ -5,7 +5,6 @@ import {By} from '@angular/platform-browser'; import {MdMonthView} from './month-view'; import {MdYearView} from './year-view'; import {MdCalendarBody} from './calendar-body'; -import {DatetimeModule} from '../core/datetime/index'; import { dispatchFakeEvent, dispatchKeyboardEvent, @@ -23,6 +22,7 @@ import { UP_ARROW } from '../core/keyboard/keycodes'; import {MdDatepickerIntl} from './datepicker-intl'; +import {MdNativeDateModule} from '../core/datetime/index'; // When constructing a Date, the month is zero-based. This can be confusing, since people are @@ -35,7 +35,7 @@ describe('MdCalendar', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - DatetimeModule, + MdNativeDateModule, ], declarations: [ MdCalendar, diff --git a/src/lib/datepicker/calendar.ts b/src/lib/datepicker/calendar.ts index fd2ccf7579cd..dad4a0d9a193 100644 --- a/src/lib/datepicker/calendar.ts +++ b/src/lib/datepicker/calendar.ts @@ -3,7 +3,9 @@ import { ChangeDetectionStrategy, Component, EventEmitter, + Inject, Input, + Optional, Output, ViewEncapsulation } from '@angular/core'; @@ -20,6 +22,8 @@ import { } from '../core/keyboard/keycodes'; import {DateAdapter} from '../core/datetime/index'; import {MdDatepickerIntl} from './datepicker-intl'; +import {createMissingDateImplError} from './datepicker-errors'; +import {MD_DATE_FORMATS, MdDateFormats} from '../core/datetime/date-formats'; /** @@ -41,7 +45,9 @@ export class MdCalendar implements AfterContentInit { /** A date representing the period (month or year) to start the calendar in. */ @Input() get startAt(): D { return this._startAt; } - set startAt(value: D) { this._startAt = this._dateAdapter.parse(value); } + set startAt(value: D) { + this._startAt = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput); + } private _startAt: D; /** Whether the calendar should be started in month or year view. */ @@ -50,19 +56,25 @@ export class MdCalendar implements AfterContentInit { /** The currently selected date. */ @Input() get selected(): D { return this._selected; } - set selected(value: D) { this._selected = this._dateAdapter.parse(value); } + set selected(value: D) { + this._selected = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput); + } private _selected: D; /** The minimum selectable date. */ @Input() get minDate(): D { return this._minDate; } - set minDate(date: D) { this._minDate = this._dateAdapter.parse(date); } + set minDate(date: D) { + this._minDate = this._dateAdapter.parse(date, this._dateFormats.parse.dateInput); + } private _minDate: D; /** The maximum selectable date. */ @Input() get maxDate(): D { return this._maxDate; } - set maxDate(date: D) { this._maxDate = this._dateAdapter.parse(date); } + set maxDate(date: D) { + this._maxDate = this._dateAdapter.parse(date, this._dateFormats.parse.dateInput); + } private _maxDate: D; /** A function used to filter which dates are selectable. */ @@ -95,7 +107,8 @@ export class MdCalendar implements AfterContentInit { /** The label for the current calendar view. */ get _periodButtonText(): string { return this._monthView ? - this._dateAdapter.getMonthYearName(this._activeDate, 'short').toLocaleUpperCase() : + this._dateAdapter.format(this._activeDate, this._dateFormats.display.monthYearLabel) + .toLocaleUpperCase() : this._dateAdapter.getYearName(this._activeDate); } @@ -113,7 +126,16 @@ export class MdCalendar implements AfterContentInit { return this._monthView ? this._intl.nextMonthLabel : this._intl.nextYearLabel; } - constructor(private _dateAdapter: DateAdapter, private _intl: MdDatepickerIntl) {} + constructor(private _intl: MdDatepickerIntl, + @Optional() private _dateAdapter: DateAdapter, + @Optional() @Inject(MD_DATE_FORMATS) private _dateFormats: MdDateFormats) { + if (!this._dateAdapter) { + throw createMissingDateImplError('DateAdapter'); + } + if (!this._dateFormats) { + throw createMissingDateImplError('MD_DATE_FORMATS'); + } + } ngAfterContentInit() { this._activeDate = this.startAt || this._dateAdapter.today(); diff --git a/src/lib/datepicker/datepicker-errors.ts b/src/lib/datepicker/datepicker-errors.ts new file mode 100644 index 000000000000..494b0d49232e --- /dev/null +++ b/src/lib/datepicker/datepicker-errors.ts @@ -0,0 +1,6 @@ +/** @docs-private */ +export function createMissingDateImplError(provider: string) { + return new Error( + `MdDatepicker: No provider found for ${provider}. You must import one of the following` + + `modules at your application root: MdNativeDateModule, or provide a custom implementation.`); +} diff --git a/src/lib/datepicker/datepicker-input.ts b/src/lib/datepicker/datepicker-input.ts index ea189ed57de1..a0361fbe34ad 100644 --- a/src/lib/datepicker/datepicker-input.ts +++ b/src/lib/datepicker/datepicker-input.ts @@ -4,6 +4,7 @@ import { ElementRef, EventEmitter, forwardRef, + Inject, Input, OnDestroy, Optional, @@ -15,6 +16,8 @@ import {Subscription} from 'rxjs/Subscription'; import {MdInputContainer} from '../input/input-container'; import {DOWN_ARROW} from '../core/keyboard/keycodes'; import {DateAdapter} from '../core/datetime/index'; +import {createMissingDateImplError} from './datepicker-errors'; +import {MD_DATE_FORMATS, MdDateFormats} from '../core/datetime/date-formats'; export const MD_DATEPICKER_VALUE_ACCESSOR: any = { @@ -56,13 +59,14 @@ export class MdDatepickerInput implements AfterContentInit, ControlValueAcces /** The value of the input. */ @Input() get value(): D { - return this._dateAdapter.parse(this._elementRef.nativeElement.value); + return this._dateAdapter.parse(this._elementRef.nativeElement.value, + this._dateFormats.parse.dateInput); } set value(value: D) { - let date = this._dateAdapter.parse(value); + let date = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput); let oldDate = this.value; this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', - date ? this._dateAdapter.format(date) : ''); + date ? this._dateAdapter.format(date, this._dateFormats.display.dateInput) : ''); if (!this._dateAdapter.sameDate(oldDate, date)) { this._valueChange.emit(date); } @@ -71,13 +75,17 @@ export class MdDatepickerInput implements AfterContentInit, ControlValueAcces /** The minimum valid date. */ @Input() get min(): D { return this._min; } - set min(value: D) { this._min = this._dateAdapter.parse(value); } + set min(value: D) { + this._min = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput); + } private _min: D; /** The maximum valid date. */ @Input() get max(): D { return this._max; } - set max(value: D) { this._max = this._dateAdapter.parse(value); } + set max(value: D) { + this._max = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput); + } private _max: D; /** Emits when the value changes (either due to user input or programmatic change). */ @@ -92,8 +100,16 @@ export class MdDatepickerInput implements AfterContentInit, ControlValueAcces constructor( private _elementRef: ElementRef, private _renderer: Renderer, - private _dateAdapter: DateAdapter, - @Optional() private _mdInputContainer: MdInputContainer) {} + @Optional() private _dateAdapter: DateAdapter, + @Optional() @Inject(MD_DATE_FORMATS) private _dateFormats: MdDateFormats, + @Optional() private _mdInputContainer: MdInputContainer) { + if (!this._dateAdapter) { + throw createMissingDateImplError('DateAdapter'); + } + if (!this._dateFormats) { + throw createMissingDateImplError('MD_DATE_FORMATS'); + } + } ngAfterContentInit() { if (this._datepicker) { @@ -147,7 +163,7 @@ export class MdDatepickerInput implements AfterContentInit, ControlValueAcces } _onInput(value: string) { - let date = this._dateAdapter.parse(value); + let date = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput); this._onChange(date); this._valueChange.emit(date); } diff --git a/src/lib/datepicker/datepicker-intl.ts b/src/lib/datepicker/datepicker-intl.ts index a96ea07b12f7..973bf29cccef 100644 --- a/src/lib/datepicker/datepicker-intl.ts +++ b/src/lib/datepicker/datepicker-intl.ts @@ -27,10 +27,4 @@ export class MdDatepickerIntl { /** A label for the 'switch to year view' button (used by screen readers). */ switchToYearViewLabel = 'Change to year view'; - - /** - * The format to use when displaying dates without time information. If unspecified the `date` - * format supplied by {@link DateAdapter#getDefaultFormats} will be used. - */ - dateFormat: any; } diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index dd8872161be9..be161e143591 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -8,6 +8,7 @@ import {By} from '@angular/platform-browser'; import {dispatchFakeEvent, dispatchMouseEvent} from '../core/testing/dispatch-events'; import {MdInputModule} from '../input/index'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {MdNativeDateModule} from '../core/datetime/index'; // When constructing a Date, the month is zero-based. This can be confusing, since people are @@ -17,412 +18,447 @@ const JAN = 0, FEB = 1, MAR = 2, APR = 3, MAY = 4, JUN = 5, JUL = 6, AUG = 7, SE describe('MdDatepicker', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - FormsModule, - MdDatepickerModule, - MdInputModule, - NoopAnimationsModule, - ReactiveFormsModule, - ], - declarations: [ - DatepickerWithFormControl, - DatepickerWithMinAndMax, - DatepickerWithNgModel, - DatepickerWithStartAt, - DatepickerWithToggle, - InputContainerDatepicker, - MultiInputDatepicker, - NoInputDatepicker, - StandardDatepicker, - ], - }); + describe('with MdNativeDateModule', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + FormsModule, + MdDatepickerModule, + MdInputModule, + MdNativeDateModule, + NoopAnimationsModule, + ReactiveFormsModule, + ], + declarations: [ + DatepickerWithFormControl, + DatepickerWithMinAndMax, + DatepickerWithNgModel, + DatepickerWithStartAt, + DatepickerWithToggle, + InputContainerDatepicker, + MultiInputDatepicker, + NoInputDatepicker, + StandardDatepicker, + ], + }); - TestBed.compileComponents(); - })); + TestBed.compileComponents(); + })); - describe('standard datepicker', () => { - let fixture: ComponentFixture; - let testComponent: StandardDatepicker; + describe('standard datepicker', () => { + let fixture: ComponentFixture; + let testComponent: StandardDatepicker; - beforeEach(async(() => { - fixture = TestBed.createComponent(StandardDatepicker); - fixture.detectChanges(); + beforeEach(async(() => { + fixture = TestBed.createComponent(StandardDatepicker); + fixture.detectChanges(); - testComponent = fixture.componentInstance; - })); + testComponent = fixture.componentInstance; + })); - afterEach(async(() => { - testComponent.datepicker.close(); - fixture.detectChanges(); - })); + afterEach(async(() => { + testComponent.datepicker.close(); + fixture.detectChanges(); + })); + + it('open non-touch should open popup', async(() => { + expect(document.querySelector('.cdk-overlay-pane')).toBeNull(); - it('open non-touch should open popup', async(() => { - expect(document.querySelector('.cdk-overlay-pane')).toBeNull(); + testComponent.datepicker.open(); + fixture.detectChanges(); - testComponent.datepicker.open(); - fixture.detectChanges(); + expect(document.querySelector('.cdk-overlay-pane')).not.toBeNull(); + })); - expect(document.querySelector('.cdk-overlay-pane')).not.toBeNull(); - })); + it('open touch should open dialog', async(() => { + testComponent.touch = true; + fixture.detectChanges(); - it('open touch should open dialog', async(() => { - testComponent.touch = true; - fixture.detectChanges(); + expect(document.querySelector('md-dialog-container')).toBeNull(); - expect(document.querySelector('md-dialog-container')).toBeNull(); + testComponent.datepicker.open(); + fixture.detectChanges(); - testComponent.datepicker.open(); - fixture.detectChanges(); + expect(document.querySelector('md-dialog-container')).not.toBeNull(); + })); - expect(document.querySelector('md-dialog-container')).not.toBeNull(); - })); + it('close should close popup', async(() => { + testComponent.datepicker.open(); + fixture.detectChanges(); - it('close should close popup', async(() => { - testComponent.datepicker.open(); - fixture.detectChanges(); + let popup = document.querySelector('.cdk-overlay-pane'); + expect(popup).not.toBeNull(); + expect(parseInt(getComputedStyle(popup).height)).not.toBe(0); - let popup = document.querySelector('.cdk-overlay-pane'); - expect(popup).not.toBeNull(); - expect(parseInt(getComputedStyle(popup).height)).not.toBe(0); + testComponent.datepicker.close(); + fixture.detectChanges(); - testComponent.datepicker.close(); - fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(parseInt(getComputedStyle(popup).height)).toBe(0); + }); + })); - fixture.whenStable().then(() => { - expect(parseInt(getComputedStyle(popup).height)).toBe(0); - }); - })); + it('close should close dialog', async(() => { + testComponent.touch = true; + fixture.detectChanges(); - it('close should close dialog', async(() => { - testComponent.touch = true; - fixture.detectChanges(); + testComponent.datepicker.open(); + fixture.detectChanges(); - testComponent.datepicker.open(); - fixture.detectChanges(); + expect(document.querySelector('md-dialog-container')).not.toBeNull(); - expect(document.querySelector('md-dialog-container')).not.toBeNull(); + testComponent.datepicker.close(); + fixture.detectChanges(); - testComponent.datepicker.close(); - fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(document.querySelector('md-dialog-container')).toBeNull(); + }); + })); - fixture.whenStable().then(() => { - expect(document.querySelector('md-dialog-container')).toBeNull(); - }); - })); + it('setting selected should update input and close calendar', async(() => { + testComponent.touch = true; + fixture.detectChanges(); - it('setting selected should update input and close calendar', async(() => { - testComponent.touch = true; - fixture.detectChanges(); + testComponent.datepicker.open(); + fixture.detectChanges(); - testComponent.datepicker.open(); - fixture.detectChanges(); + expect(document.querySelector('md-dialog-container')).not.toBeNull(); + expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 1)); - expect(document.querySelector('md-dialog-container')).not.toBeNull(); - expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 1)); + let cells = document.querySelectorAll('.mat-calendar-body-cell'); + dispatchMouseEvent(cells[1], 'click'); + fixture.detectChanges(); - let cells = document.querySelectorAll('.mat-calendar-body-cell'); - dispatchMouseEvent(cells[1], 'click'); - fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(document.querySelector('md-dialog-container')).toBeNull(); + expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2)); + }); + })); - fixture.whenStable().then(() => { - expect(document.querySelector('md-dialog-container')).toBeNull(); - expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2)); + it('startAt should fallback to input value', () => { + expect(testComponent.datepicker.startAt).toEqual(new Date(2020, JAN, 1)); }); - })); - it('startAt should fallback to input value', () => { - expect(testComponent.datepicker.startAt).toEqual(new Date(2020, JAN, 1)); + it('should attach popup to native input', () => { + let attachToRef = testComponent.datepickerInput.getPopupConnectionElementRef(); + expect(attachToRef.nativeElement.tagName.toLowerCase()) + .toBe('input', 'popup should be attached to native input'); + }); }); - it('should attach popup to native input', () => { - let attachToRef = testComponent.datepickerInput.getPopupConnectionElementRef(); - expect(attachToRef.nativeElement.tagName.toLowerCase()) - .toBe('input', 'popup should be attached to native input'); + describe('datepicker with too many inputs', () => { + it('should throw when multiple inputs registered', async(() => { + let fixture = TestBed.createComponent(MultiInputDatepicker); + expect(() => fixture.detectChanges()).toThrow(); + })); }); - }); - describe('datepicker with too many inputs', () => { - it('should throw when multiple inputs registered', async(() => { - let fixture = TestBed.createComponent(MultiInputDatepicker); - expect(() => fixture.detectChanges()).toThrow(); - })); - }); - - describe('datepicker with no inputs', () => { - let fixture: ComponentFixture; - let testComponent: NoInputDatepicker; + describe('datepicker with no inputs', () => { + let fixture: ComponentFixture; + let testComponent: NoInputDatepicker; - beforeEach(async(() => { - fixture = TestBed.createComponent(NoInputDatepicker); - fixture.detectChanges(); + beforeEach(async(() => { + fixture = TestBed.createComponent(NoInputDatepicker); + fixture.detectChanges(); - testComponent = fixture.componentInstance; - })); + testComponent = fixture.componentInstance; + })); - afterEach(async(() => { - testComponent.datepicker.close(); - fixture.detectChanges(); - })); + afterEach(async(() => { + testComponent.datepicker.close(); + fixture.detectChanges(); + })); - it('should throw when opened with no registered inputs', async(() => { - expect(() => testComponent.datepicker.open()).toThrow(); - })); - }); + it('should throw when opened with no registered inputs', async(() => { + expect(() => testComponent.datepicker.open()).toThrow(); + })); + }); - describe('datepicker with startAt', () => { - let fixture: ComponentFixture; - let testComponent: DatepickerWithStartAt; + describe('datepicker with startAt', () => { + let fixture: ComponentFixture; + let testComponent: DatepickerWithStartAt; - beforeEach(async(() => { - fixture = TestBed.createComponent(DatepickerWithStartAt); - fixture.detectChanges(); + beforeEach(async(() => { + fixture = TestBed.createComponent(DatepickerWithStartAt); + fixture.detectChanges(); - testComponent = fixture.componentInstance; - })); + testComponent = fixture.componentInstance; + })); - afterEach(async(() => { - testComponent.datepicker.close(); - fixture.detectChanges(); - })); + afterEach(async(() => { + testComponent.datepicker.close(); + fixture.detectChanges(); + })); - it('explicit startAt should override input value', () => { - expect(testComponent.datepicker.startAt).toEqual(new Date(2010, JAN, 1)); + it('explicit startAt should override input value', () => { + expect(testComponent.datepicker.startAt).toEqual(new Date(2010, JAN, 1)); + }); }); - }); - describe('datepicker with ngModel', () => { - let fixture: ComponentFixture; - let testComponent: DatepickerWithNgModel; + describe('datepicker with ngModel', () => { + let fixture: ComponentFixture; + let testComponent: DatepickerWithNgModel; - beforeEach(async(() => { - fixture = TestBed.createComponent(DatepickerWithNgModel); - fixture.detectChanges(); + beforeEach(async(() => { + fixture = TestBed.createComponent(DatepickerWithNgModel); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + fixture.detectChanges(); - fixture.whenStable().then(() => { + testComponent = fixture.componentInstance; + }); + })); + + afterEach(async(() => { + testComponent.datepicker.close(); fixture.detectChanges(); + })); - testComponent = fixture.componentInstance; - }); - })); + it('should update datepicker when model changes', async(() => { + expect(testComponent.datepickerInput.value).toBeNull(); + expect(testComponent.datepicker._selected).toBeNull(); - afterEach(async(() => { - testComponent.datepicker.close(); - fixture.detectChanges(); - })); + let selected = new Date(2017, JAN, 1); + testComponent.selected = selected; + fixture.detectChanges(); - it('should update datepicker when model changes', async(() => { - expect(testComponent.datepickerInput.value).toBeNull(); - expect(testComponent.datepicker._selected).toBeNull(); + fixture.whenStable().then(() => { + fixture.detectChanges(); - let selected = new Date(2017, JAN, 1); - testComponent.selected = selected; - fixture.detectChanges(); + expect(testComponent.datepickerInput.value).toEqual(selected); + expect(testComponent.datepicker._selected).toEqual(selected); + }); + })); - fixture.whenStable().then(() => { + it('should update model when date is selected', async(() => { + expect(testComponent.selected).toBeNull(); + expect(testComponent.datepickerInput.value).toBeNull(); + + let selected = new Date(2017, JAN, 1); + testComponent.datepicker._selectAndClose(selected); fixture.detectChanges(); - expect(testComponent.datepickerInput.value).toEqual(selected); - expect(testComponent.datepicker._selected).toEqual(selected); - }); - })); + fixture.whenStable().then(() => { + fixture.detectChanges(); + + expect(testComponent.selected).toEqual(selected); + expect(testComponent.datepickerInput.value).toEqual(selected); + }); + })); - it('should update model when date is selected', async(() => { - expect(testComponent.selected).toBeNull(); - expect(testComponent.datepickerInput.value).toBeNull(); + it('should mark input dirty after input event', () => { + let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; - let selected = new Date(2017, JAN, 1); - testComponent.datepicker._selectAndClose(selected); - fixture.detectChanges(); + expect(inputEl.classList).toContain('ng-pristine'); - fixture.whenStable().then(() => { + dispatchFakeEvent(inputEl, 'input'); fixture.detectChanges(); - expect(testComponent.selected).toEqual(selected); - expect(testComponent.datepickerInput.value).toEqual(selected); + expect(inputEl.classList).toContain('ng-dirty'); }); - })); - it('should mark input dirty after input event', () => { - let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; + it('should mark input dirty after date selected', async(() => { + let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; - expect(inputEl.classList).toContain('ng-pristine'); + expect(inputEl.classList).toContain('ng-pristine'); - dispatchFakeEvent(inputEl, 'input'); - fixture.detectChanges(); + testComponent.datepicker._selectAndClose(new Date(2017, JAN, 1)); + fixture.detectChanges(); - expect(inputEl.classList).toContain('ng-dirty'); - }); + fixture.whenStable().then(() => { + fixture.detectChanges(); - it('should mark input dirty after date selected', async(() => { - let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; + expect(inputEl.classList).toContain('ng-dirty'); + }); + })); - expect(inputEl.classList).toContain('ng-pristine'); + it('should not mark dirty after model change', async(() => { + let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; - testComponent.datepicker._selectAndClose(new Date(2017, JAN, 1)); - fixture.detectChanges(); + expect(inputEl.classList).toContain('ng-pristine'); - fixture.whenStable().then(() => { + testComponent.selected = new Date(2017, JAN, 1); fixture.detectChanges(); - expect(inputEl.classList).toContain('ng-dirty'); - }); - })); + fixture.whenStable().then(() => { + fixture.detectChanges(); - it('should not mark dirty after model change', async(() => { - let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; + expect(inputEl.classList).toContain('ng-pristine'); + }); + })); - expect(inputEl.classList).toContain('ng-pristine'); + it('should mark input touched on blur', () => { + let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; - testComponent.selected = new Date(2017, JAN, 1); - fixture.detectChanges(); + expect(inputEl.classList).toContain('ng-untouched'); - fixture.whenStable().then(() => { + dispatchFakeEvent(inputEl, 'focus'); fixture.detectChanges(); - expect(inputEl.classList).toContain('ng-pristine'); - }); - })); + expect(inputEl.classList).toContain('ng-untouched'); - it('should mark input touched on blur', () => { - let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; + dispatchFakeEvent(inputEl, 'blur'); + fixture.detectChanges(); - expect(inputEl.classList).toContain('ng-untouched'); + expect(inputEl.classList).toContain('ng-touched'); + }); + }); - dispatchFakeEvent(inputEl, 'focus'); - fixture.detectChanges(); + describe('datepicker with formControl', () => { + let fixture: ComponentFixture; + let testComponent: DatepickerWithFormControl; - expect(inputEl.classList).toContain('ng-untouched'); + beforeEach(async(() => { + fixture = TestBed.createComponent(DatepickerWithFormControl); + fixture.detectChanges(); - dispatchFakeEvent(inputEl, 'blur'); - fixture.detectChanges(); + testComponent = fixture.componentInstance; + })); - expect(inputEl.classList).toContain('ng-touched'); - }); - }); + afterEach(async(() => { + testComponent.datepicker.close(); + fixture.detectChanges(); + })); - describe('datepicker with formControl', () => { - let fixture: ComponentFixture; - let testComponent: DatepickerWithFormControl; + it('should update datepicker when formControl changes', () => { + expect(testComponent.datepickerInput.value).toBeNull(); + expect(testComponent.datepicker._selected).toBeNull(); - beforeEach(async(() => { - fixture = TestBed.createComponent(DatepickerWithFormControl); - fixture.detectChanges(); + let selected = new Date(2017, JAN, 1); + testComponent.formControl.setValue(selected); + fixture.detectChanges(); - testComponent = fixture.componentInstance; - })); + expect(testComponent.datepickerInput.value).toEqual(selected); + expect(testComponent.datepicker._selected).toEqual(selected); + }); - afterEach(async(() => { - testComponent.datepicker.close(); - fixture.detectChanges(); - })); + it('should update formControl when date is selected', () => { + expect(testComponent.formControl.value).toBeNull(); + expect(testComponent.datepickerInput.value).toBeNull(); - it('should update datepicker when formControl changes', () => { - expect(testComponent.datepickerInput.value).toBeNull(); - expect(testComponent.datepicker._selected).toBeNull(); + let selected = new Date(2017, JAN, 1); + testComponent.datepicker._selectAndClose(selected); + fixture.detectChanges(); - let selected = new Date(2017, JAN, 1); - testComponent.formControl.setValue(selected); - fixture.detectChanges(); + expect(testComponent.formControl.value).toEqual(selected); + expect(testComponent.datepickerInput.value).toEqual(selected); + }); - expect(testComponent.datepickerInput.value).toEqual(selected); - expect(testComponent.datepicker._selected).toEqual(selected); - }); + it('should disable input when form control disabled', () => { + let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; - it('should update formControl when date is selected', () => { - expect(testComponent.formControl.value).toBeNull(); - expect(testComponent.datepickerInput.value).toBeNull(); + expect(inputEl.disabled).toBe(false); - let selected = new Date(2017, JAN, 1); - testComponent.datepicker._selectAndClose(selected); - fixture.detectChanges(); + testComponent.formControl.disable(); + fixture.detectChanges(); - expect(testComponent.formControl.value).toEqual(selected); - expect(testComponent.datepickerInput.value).toEqual(selected); + expect(inputEl.disabled).toBe(true); + }); }); - it('should disable input when form control disabled', () => { - let inputEl = fixture.debugElement.query(By.css('input')).nativeElement; + describe('datepicker with mdDatepickerToggle', () => { + let fixture: ComponentFixture; + let testComponent: DatepickerWithToggle; - expect(inputEl.disabled).toBe(false); + beforeEach(async(() => { + fixture = TestBed.createComponent(DatepickerWithToggle); + fixture.detectChanges(); - testComponent.formControl.disable(); - fixture.detectChanges(); + testComponent = fixture.componentInstance; + })); - expect(inputEl.disabled).toBe(true); - }); - }); + afterEach(async(() => { + testComponent.datepicker.close(); + fixture.detectChanges(); + })); - describe('datepicker with mdDatepickerToggle', () => { - let fixture: ComponentFixture; - let testComponent: DatepickerWithToggle; + it('should open calendar when toggle clicked', async(() => { + expect(document.querySelector('md-dialog-container')).toBeNull(); - beforeEach(async(() => { - fixture = TestBed.createComponent(DatepickerWithToggle); - fixture.detectChanges(); + let toggle = fixture.debugElement.query(By.css('button')); + dispatchMouseEvent(toggle.nativeElement, 'click'); + fixture.detectChanges(); - testComponent = fixture.componentInstance; - })); + expect(document.querySelector('md-dialog-container')).not.toBeNull(); + })); + }); - afterEach(async(() => { - testComponent.datepicker.close(); - fixture.detectChanges(); - })); + describe('datepicker inside input-container', () => { + let fixture: ComponentFixture; + let testComponent: InputContainerDatepicker; - it('should open calendar when toggle clicked', async(() => { - expect(document.querySelector('md-dialog-container')).toBeNull(); + beforeEach(async(() => { + fixture = TestBed.createComponent(InputContainerDatepicker); + fixture.detectChanges(); - let toggle = fixture.debugElement.query(By.css('button')); - dispatchMouseEvent(toggle.nativeElement, 'click'); - fixture.detectChanges(); + testComponent = fixture.componentInstance; + })); - expect(document.querySelector('md-dialog-container')).not.toBeNull(); - })); - }); + afterEach(async(() => { + testComponent.datepicker.close(); + fixture.detectChanges(); + })); - describe('datepicker inside input-container', () => { - let fixture: ComponentFixture; - let testComponent: InputContainerDatepicker; + it('should attach popup to input-container underline', () => { + let attachToRef = testComponent.datepickerInput.getPopupConnectionElementRef(); + expect(attachToRef.nativeElement.classList.contains('mat-input-underline')) + .toBe(true, 'popup should be attached to input-container underline'); + }); + }); - beforeEach(async(() => { - fixture = TestBed.createComponent(InputContainerDatepicker); - fixture.detectChanges(); + describe('datepicker with min and max dates', () => { + let fixture: ComponentFixture; + let testComponent: DatepickerWithMinAndMax; - testComponent = fixture.componentInstance; - })); + beforeEach(async(() => { + fixture = TestBed.createComponent(DatepickerWithMinAndMax); + fixture.detectChanges(); - afterEach(async(() => { - testComponent.datepicker.close(); - fixture.detectChanges(); - })); + testComponent = fixture.componentInstance; + })); + + afterEach(async(() => { + testComponent.datepicker.close(); + fixture.detectChanges(); + })); - it('should attach popup to input-container underline', () => { - let attachToRef = testComponent.datepickerInput.getPopupConnectionElementRef(); - expect(attachToRef.nativeElement.classList.contains('mat-input-underline')) - .toBe(true, 'popup should be attached to input-container underline'); + it('should use min and max dates specified by the input', () => { + expect(testComponent.datepicker._minDate).toEqual(new Date(2010, JAN, 1)); + expect(testComponent.datepicker._maxDate).toEqual(new Date(2020, JAN, 1)); + }); }); }); - describe('datepicker with min and max dates', () => { - let fixture: ComponentFixture; - let testComponent: DatepickerWithMinAndMax; - + describe('with missing DateAdapter and MD_DATE_FORMATS', () => { beforeEach(async(() => { - fixture = TestBed.createComponent(DatepickerWithMinAndMax); - fixture.detectChanges(); - - testComponent = fixture.componentInstance; - })); + TestBed.configureTestingModule({ + imports: [ + FormsModule, + MdDatepickerModule, + MdInputModule, + NoopAnimationsModule, + ReactiveFormsModule, + ], + declarations: [ + DatepickerWithFormControl, + DatepickerWithMinAndMax, + DatepickerWithNgModel, + DatepickerWithStartAt, + DatepickerWithToggle, + InputContainerDatepicker, + MultiInputDatepicker, + NoInputDatepicker, + StandardDatepicker, + ], + }); - afterEach(async(() => { - testComponent.datepicker.close(); - fixture.detectChanges(); + TestBed.compileComponents(); })); - it('should use min and max dates specified by the input', () => { - expect(testComponent.datepicker._minDate).toEqual(new Date(2010, JAN, 1)); - expect(testComponent.datepicker._maxDate).toEqual(new Date(2020, JAN, 1)); + it('should throw when created', () => { + expect(() => TestBed.createComponent(StandardDatepicker)) + .toThrowError(/MdDatepicker: No provider found for .*/); }); }); }); diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts index 9fb7129294ea..50dc30c63dfb 100644 --- a/src/lib/datepicker/datepicker.ts +++ b/src/lib/datepicker/datepicker.ts @@ -5,6 +5,7 @@ import { ComponentRef, ElementRef, EventEmitter, + Inject, Input, OnDestroy, Optional, @@ -30,6 +31,8 @@ import 'rxjs/add/operator/first'; import {Subscription} from 'rxjs/Subscription'; import {MdDialogConfig} from '../dialog/dialog-config'; import {DateAdapter} from '../core/datetime/index'; +import {createMissingDateImplError} from './datepicker-errors'; +import {MD_DATE_FORMATS, MdDateFormats} from '../core/datetime/date-formats'; /** Used to generate a unique ID for each datepicker instance. */ @@ -83,7 +86,9 @@ export class MdDatepicker implements OnDestroy { // selected value is. return this._startAt || (this._datepickerInput ? this._datepickerInput.value : null); } - set startAt(date: D) { this._startAt = this._dateAdapter.parse(date); } + set startAt(date: D) { + this._startAt = this._dateAdapter.parse(date, this._dateFormats.parse.dateInput); + } private _startAt: D; /** @@ -134,8 +139,17 @@ export class MdDatepicker implements OnDestroy { private _inputSubscription: Subscription; constructor(private _dialog: MdDialog, private _overlay: Overlay, - private _viewContainerRef: ViewContainerRef, private _dateAdapter: DateAdapter, - @Optional() private _dir: Dir) {} + private _viewContainerRef: ViewContainerRef, + @Optional() private _dateAdapter: DateAdapter, + @Optional() @Inject(MD_DATE_FORMATS) private _dateFormats: MdDateFormats, + @Optional() private _dir: Dir) { + if (!this._dateAdapter) { + throw createMissingDateImplError('DateAdapter'); + } + if (!this._dateFormats) { + throw createMissingDateImplError('MD_DATE_FORMATS'); + } + } ngOnDestroy() { this.close(); diff --git a/src/lib/datepicker/index.ts b/src/lib/datepicker/index.ts index a5fae36c6df4..186757dcc51f 100644 --- a/src/lib/datepicker/index.ts +++ b/src/lib/datepicker/index.ts @@ -3,7 +3,6 @@ import {MdMonthView} from './month-view'; import {CommonModule} from '@angular/common'; import {MdCalendarBody} from './calendar-body'; import {MdYearView} from './year-view'; -import {DatetimeModule} from '../core/datetime/index'; import {OverlayModule} from '../core/overlay/overlay-directives'; import {MdDatepicker, MdDatepickerContent} from './datepicker'; import {MdDatepickerInput} from './datepicker-input'; @@ -28,7 +27,6 @@ export * from './year-view'; @NgModule({ imports: [ CommonModule, - DatetimeModule, MdButtonModule, MdDialogModule, OverlayModule, diff --git a/src/lib/datepicker/month-view.spec.ts b/src/lib/datepicker/month-view.spec.ts index a06f21079dbd..9b74cc7f1a3a 100644 --- a/src/lib/datepicker/month-view.spec.ts +++ b/src/lib/datepicker/month-view.spec.ts @@ -3,7 +3,7 @@ import {Component} from '@angular/core'; import {By} from '@angular/platform-browser'; import {MdMonthView} from './month-view'; import {MdCalendarBody} from './calendar-body'; -import {DatetimeModule} from '../core/datetime/index'; +import {MdNativeDateModule} from '../core/datetime/index'; // When constructing a Date, the month is zero-based. This can be confusing, since people are @@ -16,7 +16,7 @@ describe('MdMonthView', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - DatetimeModule, + MdNativeDateModule, ], declarations: [ MdCalendarBody, diff --git a/src/lib/datepicker/month-view.ts b/src/lib/datepicker/month-view.ts index 8313085812bf..d18e96e9d7d5 100644 --- a/src/lib/datepicker/month-view.ts +++ b/src/lib/datepicker/month-view.ts @@ -3,12 +3,16 @@ import { ChangeDetectionStrategy, Component, EventEmitter, + Inject, Input, + Optional, Output, ViewEncapsulation } from '@angular/core'; import {MdCalendarCell} from './calendar-body'; import {DateAdapter} from '../core/datetime/index'; +import {createMissingDateImplError} from './datepicker-errors'; +import {MD_DATE_FORMATS, MdDateFormats} from '../core/datetime/date-formats'; const DAYS_PER_WEEK = 7; @@ -33,7 +37,8 @@ export class MdMonthView implements AfterContentInit { get activeDate(): D { return this._activeDate; } set activeDate(value: D) { let oldActiveDate = this._activeDate; - this._activeDate = this._dateAdapter.parse(value) || this._dateAdapter.today(); + this._activeDate = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput) || + this._dateAdapter.today(); if (!this._hasSameMonthAndYear(oldActiveDate, this._activeDate)) { this._init(); } @@ -44,7 +49,7 @@ export class MdMonthView implements AfterContentInit { @Input() get selected(): D { return this._selected; } set selected(value: D) { - this._selected = this._dateAdapter.parse(value); + this._selected = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput); this._selectedDate = this._getDateInCurrentMonth(this.selected); } private _selected: D; @@ -76,7 +81,15 @@ export class MdMonthView implements AfterContentInit { /** The names of the weekdays. */ _weekdays: string[]; - constructor(public _dateAdapter: DateAdapter) { + constructor(@Optional() public _dateAdapter: DateAdapter, + @Optional() @Inject(MD_DATE_FORMATS) private _dateFormats: MdDateFormats) { + if (!this._dateAdapter) { + throw createMissingDateImplError('DateAdapter'); + } + if (!this._dateFormats) { + throw createMissingDateImplError('MD_DATE_FORMATS'); + } + const firstDayOfWeek = this._dateAdapter.getFirstDayOfWeek(); const weekdays = this._dateAdapter.getDayOfWeekNames('narrow'); diff --git a/src/lib/datepicker/year-view.spec.ts b/src/lib/datepicker/year-view.spec.ts index 3247bfea711c..b1fcc3269dd4 100644 --- a/src/lib/datepicker/year-view.spec.ts +++ b/src/lib/datepicker/year-view.spec.ts @@ -3,7 +3,7 @@ import {Component} from '@angular/core'; import {By} from '@angular/platform-browser'; import {MdYearView} from './year-view'; import {MdCalendarBody} from './calendar-body'; -import {DatetimeModule} from '../core/datetime/index'; +import {MdNativeDateModule} from '../core/datetime/index'; // When constructing a Date, the month is zero-based. This can be confusing, since people are @@ -16,7 +16,7 @@ describe('MdYearView', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - DatetimeModule, + MdNativeDateModule, ], declarations: [ MdCalendarBody, diff --git a/src/lib/datepicker/year-view.ts b/src/lib/datepicker/year-view.ts index 5792ae263560..c8e4115a65fa 100644 --- a/src/lib/datepicker/year-view.ts +++ b/src/lib/datepicker/year-view.ts @@ -3,12 +3,16 @@ import { ChangeDetectionStrategy, Component, EventEmitter, + Inject, Input, + Optional, Output, ViewEncapsulation } from '@angular/core'; import {MdCalendarCell} from './calendar-body'; import {DateAdapter} from '../core/datetime/index'; +import {createMissingDateImplError} from './datepicker-errors'; +import {MD_DATE_FORMATS, MdDateFormats} from '../core/datetime/date-formats'; /** @@ -28,7 +32,8 @@ export class MdYearView implements AfterContentInit { get activeDate(): D { return this._activeDate; } set activeDate(value: D) { let oldActiveDate = this._activeDate; - this._activeDate = this._dateAdapter.parse(value) || this._dateAdapter.today(); + this._activeDate = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput) || + this._dateAdapter.today(); if (this._dateAdapter.getYear(oldActiveDate) != this._dateAdapter.getYear(this._activeDate)) { this._init(); } @@ -39,7 +44,7 @@ export class MdYearView implements AfterContentInit { @Input() get selected(): D { return this._selected; } set selected(value: D) { - this._selected = this._dateAdapter.parse(value); + this._selected = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput); this._selectedMonth = this._getMonthInCurrentYear(this.selected); } private _selected: D; @@ -65,7 +70,15 @@ export class MdYearView implements AfterContentInit { */ _selectedMonth: number; - constructor(public _dateAdapter: DateAdapter) { + constructor(@Optional() public _dateAdapter: DateAdapter, + @Optional() @Inject(MD_DATE_FORMATS) private _dateFormats: MdDateFormats) { + if (!this._dateAdapter) { + throw createMissingDateImplError('DateAdapter'); + } + if (!this._dateFormats) { + throw createMissingDateImplError('MD_DATE_FORMATS'); + } + this._activeDate = this._dateAdapter.today(); } diff --git a/src/lib/module.ts b/src/lib/module.ts index 0c474ceb5f42..2d676785c397 100644 --- a/src/lib/module.ts +++ b/src/lib/module.ts @@ -8,7 +8,6 @@ import { OverlayModule, A11yModule, CompatibilityModule, - DatetimeModule, } from './core/index'; import {MdButtonToggleModule} from './button-toggle/index'; @@ -72,7 +71,6 @@ const MATERIAL_MODULES = [ PlatformModule, CompatibilityModule, ObserveContentModule, - DatetimeModule, ]; /** @deprecated */