From 450389e28f3afb1f87b1ec8b21c919ad5c19fd10 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 3 Oct 2017 15:03:12 -0700 Subject: [PATCH] fix(datepicker): use disabled state from FormControl --- src/demo-app/datepicker/datepicker-demo.html | 22 ++++++++-- src/demo-app/datepicker/datepicker-demo.ts | 5 ++- src/lib/datepicker/datepicker-input.ts | 4 +- src/lib/datepicker/datepicker-toggle.ts | 43 +++++++++++--------- src/lib/datepicker/datepicker.spec.ts | 14 ++++++- src/lib/datepicker/datepicker.ts | 2 +- 6 files changed, 63 insertions(+), 27 deletions(-) diff --git a/src/demo-app/datepicker/datepicker-demo.html b/src/demo-app/datepicker/datepicker-demo.html index 127c5ec2bc8d..03de75ca83de 100644 --- a/src/demo-app/datepicker/datepicker-demo.html +++ b/src/demo-app/datepicker/datepicker-demo.html @@ -94,14 +94,30 @@

Input disabled datepicker

-

Input disabled, datepicker popup enabled

+

Input disabled via FormControl

- + + + + +

+ +

Input disabled, datepicker popup enabled

+

+ + + -

diff --git a/src/demo-app/datepicker/datepicker-demo.ts b/src/demo-app/datepicker/datepicker-demo.ts index fe363d322b5e..974ea3ec4e63 100644 --- a/src/demo-app/datepicker/datepicker-demo.ts +++ b/src/demo-app/datepicker/datepicker-demo.ts @@ -1,5 +1,6 @@ import {ChangeDetectionStrategy, Component} from '@angular/core'; -import {MatDatepickerInputEvent} from '@angular/material'; +import {FormControl} from '@angular/forms'; +import {MatDatepickerInputEvent} from '@angular/material/datepicker'; @Component({ @@ -26,4 +27,6 @@ export class DatepickerDemo { onDateInput = (e: MatDatepickerInputEvent) => this.lastDateInput = e.value; onDateChange = (e: MatDatepickerInputEvent) => this.lastDateChange = e.value; + + dateCtrl = new FormControl(); } diff --git a/src/lib/datepicker/datepicker-input.ts b/src/lib/datepicker/datepicker-input.ts index fc3fee065f54..290e5202445f 100644 --- a/src/lib/datepicker/datepicker-input.ts +++ b/src/lib/datepicker/datepicker-input.ts @@ -147,7 +147,7 @@ export class MatDatepickerInput implements AfterContentInit, ControlValueAcce /** Whether the datepicker-input is disabled. */ @Input() - get disabled() { return this._disabled; } + get disabled() { return !!this._disabled; } set disabled(value: any) { const newValue = coerceBooleanProperty(value); @@ -289,7 +289,7 @@ export class MatDatepickerInput implements AfterContentInit, ControlValueAcce // Implemented as part of ControlValueAccessor setDisabledState(disabled: boolean): void { - this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', disabled); + this.disabled = disabled; } _onKeydown(event: KeyboardEvent) { diff --git a/src/lib/datepicker/datepicker-toggle.ts b/src/lib/datepicker/datepicker-toggle.ts index ff84a574f3a2..4b49c32e2c9b 100644 --- a/src/lib/datepicker/datepicker-toggle.ts +++ b/src/lib/datepicker/datepicker-toggle.ts @@ -6,7 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import {coerceBooleanProperty} from '@angular/cdk/coercion'; import { + AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, @@ -16,12 +18,11 @@ import { SimpleChanges, ViewEncapsulation, } from '@angular/core'; -import {MatDatepicker} from './datepicker'; -import {MatDatepickerIntl} from './datepicker-intl'; -import {coerceBooleanProperty} from '@angular/cdk/coercion'; -import {Subscription} from 'rxjs/Subscription'; import {merge} from 'rxjs/observable/merge'; import {of as observableOf} from 'rxjs/observable/of'; +import {Subscription} from 'rxjs/Subscription'; +import {MatDatepicker} from './datepicker'; +import {MatDatepickerIntl} from './datepicker-intl'; @Component({ @@ -35,7 +36,7 @@ import {of as observableOf} from 'rxjs/observable/of'; preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, }) -export class MatDatepickerToggle implements OnChanges, OnDestroy { +export class MatDatepickerToggle implements AfterContentInit, OnChanges, OnDestroy { private _stateChanges = Subscription.EMPTY; /** Datepicker instance that the button will toggle. */ @@ -44,28 +45,18 @@ export class MatDatepickerToggle implements OnChanges, OnDestroy { /** Whether the toggle button is disabled. */ @Input() get disabled(): boolean { - return this._disabled === undefined ? this.datepicker.disabled : this._disabled; + return this._disabled === undefined ? this.datepicker.disabled : !!this._disabled; } - set disabled(value) { + set disabled(value: boolean) { this._disabled = coerceBooleanProperty(value); } private _disabled: boolean; - constructor( - public _intl: MatDatepickerIntl, - private _changeDetectorRef: ChangeDetectorRef) {} + constructor(public _intl: MatDatepickerIntl, private _changeDetectorRef: ChangeDetectorRef) {} ngOnChanges(changes: SimpleChanges) { if (changes.datepicker) { - const datepicker: MatDatepicker = changes.datepicker.currentValue; - const datepickerDisabled = datepicker ? datepicker._disabledChange : observableOf(); - const inputDisabled = datepicker && datepicker._datepickerInput ? - datepicker._datepickerInput._disabledChange : - observableOf(); - - this._stateChanges.unsubscribe(); - this._stateChanges = merge(this._intl.changes, datepickerDisabled, inputDisabled) - .subscribe(() => this._changeDetectorRef.markForCheck()); + this._watchStateChanges(); } } @@ -73,10 +64,24 @@ export class MatDatepickerToggle implements OnChanges, OnDestroy { this._stateChanges.unsubscribe(); } + ngAfterContentInit() { + this._watchStateChanges(); + } + _open(event: Event): void { if (this.datepicker && !this.disabled) { this.datepicker.open(); event.stopPropagation(); } } + + private _watchStateChanges() { + const datepickerDisabled = this.datepicker ? this.datepicker._disabledChange : observableOf(); + const inputDisabled = this.datepicker && this.datepicker._datepickerInput ? + this.datepicker._datepickerInput._disabledChange : observableOf(); + + this._stateChanges.unsubscribe(); + this._stateChanges = merge(this._intl.changes, datepickerDisabled, inputDisabled) + .subscribe(() => this._changeDetectorRef.markForCheck()); + } } diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index dfcf2df0a509..919539a44db3 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -25,6 +25,7 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import {MatInputModule} from '../input/index'; import {MatDatepicker} from './datepicker'; import {MatDatepickerInput} from './datepicker-input'; +import {MatDatepickerToggle} from './datepicker-toggle'; import {MatDatepickerIntl, MatDatepickerModule} from './index'; @@ -539,6 +540,15 @@ describe('MatDatepicker', () => { expect(inputEl.disabled).toBe(true); }); + + it('should disable toggle when form control disabled', () => { + expect(testComponent.datepickerToggle.disabled).toBe(false); + + testComponent.formControl.disable(); + fixture.detectChanges(); + + expect(testComponent.datepickerToggle.disabled).toBe(true); + }); }); describe('datepicker with mat-datepicker-toggle', () => { @@ -582,7 +592,7 @@ describe('MatDatepicker', () => { }); it('should not open calendar when toggle clicked if input is disabled', () => { - expect(testComponent.datepicker.disabled).toBeUndefined(); + expect(testComponent.datepicker.disabled).toBe(false); testComponent.input.disabled = true; fixture.detectChanges(); @@ -1120,6 +1130,7 @@ class DatepickerWithNgModel { @Component({ template: ` + `, }) @@ -1127,6 +1138,7 @@ class DatepickerWithFormControl { formControl = new FormControl(); @ViewChild('d') datepicker: MatDatepicker; @ViewChild(MatDatepickerInput) datepickerInput: MatDatepickerInput; + @ViewChild(MatDatepickerToggle) datepickerToggle: MatDatepickerToggle; } diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts index 0793be2dc4e5..0ad4789b2f4a 100644 --- a/src/lib/datepicker/datepicker.ts +++ b/src/lib/datepicker/datepicker.ts @@ -149,7 +149,7 @@ export class MatDatepicker implements OnDestroy { @Input() get disabled() { return this._disabled === undefined && this._datepickerInput ? - this._datepickerInput.disabled : this._disabled; + this._datepickerInput.disabled : !!this._disabled; } set disabled(value: any) { const newValue = coerceBooleanProperty(value);