Skip to content

Commit 66e71c8

Browse files
mmalerbakara
authored andcommitted
fix(datepicker): use disabled state from FormControl (#7514)
1 parent 4bb696e commit 66e71c8

File tree

6 files changed

+63
-27
lines changed

6 files changed

+63
-27
lines changed

src/demo-app/datepicker/datepicker-demo.html

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,30 @@ <h2>Input disabled datepicker</h2>
9494
</mat-form-field>
9595
</p>
9696

97-
<h2>Input disabled, datepicker popup enabled</h2>
97+
<h2>Input disabled via FormControl</h2>
9898
<p>
9999
<mat-datepicker-toggle [for]="datePicker2"></mat-datepicker-toggle>
100100
<mat-form-field>
101-
<input matInput disabled [matDatepicker]="datePicker2" [(ngModel)]="date" [min]="minDate"
101+
<input matInput [matDatepicker]="datePicker2" [formControl]="dateCtrl" [min]="minDate"
102+
[max]="maxDate" [matDatepickerFilter]="filterOdd ? dateFilter : null"
103+
placeholder="FormControl disabled">
104+
<mat-datepicker #datePicker2 [touchUi]="touch" [startAt]="startAt"
105+
[startView]="yearView ? 'year' : 'month'"></mat-datepicker>
106+
</mat-form-field>
107+
108+
<button mat-button (click)="dateCtrl.disabled ? dateCtrl.enable() : dateCtrl.disable()">
109+
{{dateCtrl.disabled ? 'Enable' : 'Disable'}} FormControl
110+
</button>
111+
</p>
112+
113+
<h2>Input disabled, datepicker popup enabled</h2>
114+
<p>
115+
<mat-datepicker-toggle [for]="datePicker3"></mat-datepicker-toggle>
116+
<mat-form-field>
117+
<input matInput disabled [matDatepicker]="datePicker3" [(ngModel)]="date" [min]="minDate"
102118
[max]="maxDate" [matDatepickerFilter]="filterOdd ? dateFilter : null"
103119
placeholder="Input disabled, datepicker enabled">
104-
<mat-datepicker #datePicker2 [touchUi]="touch" [disabled]="false" [startAt]="startAt"
120+
<mat-datepicker #datePicker3 [touchUi]="touch" [disabled]="false" [startAt]="startAt"
105121
[startView]="yearView ? 'year' : 'month'"></mat-datepicker>
106122
</mat-form-field>
107123
</p>

src/demo-app/datepicker/datepicker-demo.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {ChangeDetectionStrategy, Component} from '@angular/core';
2-
import {MatDatepickerInputEvent} from '@angular/material';
2+
import {FormControl} from '@angular/forms';
3+
import {MatDatepickerInputEvent} from '@angular/material/datepicker';
34

45

56
@Component({
@@ -26,4 +27,6 @@ export class DatepickerDemo {
2627

2728
onDateInput = (e: MatDatepickerInputEvent<Date>) => this.lastDateInput = e.value;
2829
onDateChange = (e: MatDatepickerInputEvent<Date>) => this.lastDateChange = e.value;
30+
31+
dateCtrl = new FormControl();
2932
}

src/lib/datepicker/datepicker-input.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export class MatDatepickerInput<D> implements AfterContentInit, ControlValueAcce
147147

148148
/** Whether the datepicker-input is disabled. */
149149
@Input()
150-
get disabled() { return this._disabled; }
150+
get disabled() { return !!this._disabled; }
151151
set disabled(value: any) {
152152
const newValue = coerceBooleanProperty(value);
153153

@@ -289,7 +289,7 @@ export class MatDatepickerInput<D> implements AfterContentInit, ControlValueAcce
289289

290290
// Implemented as part of ControlValueAccessor
291291
setDisabledState(disabled: boolean): void {
292-
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', disabled);
292+
this.disabled = disabled;
293293
}
294294

295295
_onKeydown(event: KeyboardEvent) {

src/lib/datepicker/datepicker-toggle.ts

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {coerceBooleanProperty} from '@angular/cdk/coercion';
910
import {
11+
AfterContentInit,
1012
ChangeDetectionStrategy,
1113
ChangeDetectorRef,
1214
Component,
@@ -16,12 +18,11 @@ import {
1618
SimpleChanges,
1719
ViewEncapsulation,
1820
} from '@angular/core';
19-
import {MatDatepicker} from './datepicker';
20-
import {MatDatepickerIntl} from './datepicker-intl';
21-
import {coerceBooleanProperty} from '@angular/cdk/coercion';
22-
import {Subscription} from 'rxjs/Subscription';
2321
import {merge} from 'rxjs/observable/merge';
2422
import {of as observableOf} from 'rxjs/observable/of';
23+
import {Subscription} from 'rxjs/Subscription';
24+
import {MatDatepicker} from './datepicker';
25+
import {MatDatepickerIntl} from './datepicker-intl';
2526

2627

2728
@Component({
@@ -35,7 +36,7 @@ import {of as observableOf} from 'rxjs/observable/of';
3536
preserveWhitespaces: false,
3637
changeDetection: ChangeDetectionStrategy.OnPush,
3738
})
38-
export class MatDatepickerToggle<D> implements OnChanges, OnDestroy {
39+
export class MatDatepickerToggle<D> implements AfterContentInit, OnChanges, OnDestroy {
3940
private _stateChanges = Subscription.EMPTY;
4041

4142
/** Datepicker instance that the button will toggle. */
@@ -44,39 +45,43 @@ export class MatDatepickerToggle<D> implements OnChanges, OnDestroy {
4445
/** Whether the toggle button is disabled. */
4546
@Input()
4647
get disabled(): boolean {
47-
return this._disabled === undefined ? this.datepicker.disabled : this._disabled;
48+
return this._disabled === undefined ? this.datepicker.disabled : !!this._disabled;
4849
}
49-
set disabled(value) {
50+
set disabled(value: boolean) {
5051
this._disabled = coerceBooleanProperty(value);
5152
}
5253
private _disabled: boolean;
5354

54-
constructor(
55-
public _intl: MatDatepickerIntl,
56-
private _changeDetectorRef: ChangeDetectorRef) {}
55+
constructor(public _intl: MatDatepickerIntl, private _changeDetectorRef: ChangeDetectorRef) {}
5756

5857
ngOnChanges(changes: SimpleChanges) {
5958
if (changes.datepicker) {
60-
const datepicker: MatDatepicker<D> = changes.datepicker.currentValue;
61-
const datepickerDisabled = datepicker ? datepicker._disabledChange : observableOf();
62-
const inputDisabled = datepicker && datepicker._datepickerInput ?
63-
datepicker._datepickerInput._disabledChange :
64-
observableOf();
65-
66-
this._stateChanges.unsubscribe();
67-
this._stateChanges = merge(this._intl.changes, datepickerDisabled, inputDisabled)
68-
.subscribe(() => this._changeDetectorRef.markForCheck());
59+
this._watchStateChanges();
6960
}
7061
}
7162

7263
ngOnDestroy() {
7364
this._stateChanges.unsubscribe();
7465
}
7566

67+
ngAfterContentInit() {
68+
this._watchStateChanges();
69+
}
70+
7671
_open(event: Event): void {
7772
if (this.datepicker && !this.disabled) {
7873
this.datepicker.open();
7974
event.stopPropagation();
8075
}
8176
}
77+
78+
private _watchStateChanges() {
79+
const datepickerDisabled = this.datepicker ? this.datepicker._disabledChange : observableOf();
80+
const inputDisabled = this.datepicker && this.datepicker._datepickerInput ?
81+
this.datepicker._datepickerInput._disabledChange : observableOf();
82+
83+
this._stateChanges.unsubscribe();
84+
this._stateChanges = merge(this._intl.changes, datepickerDisabled, inputDisabled)
85+
.subscribe(() => this._changeDetectorRef.markForCheck());
86+
}
8287
}

src/lib/datepicker/datepicker.spec.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations';
2525
import {MatInputModule} from '../input/index';
2626
import {MatDatepicker} from './datepicker';
2727
import {MatDatepickerInput} from './datepicker-input';
28+
import {MatDatepickerToggle} from './datepicker-toggle';
2829
import {MatDatepickerIntl, MatDatepickerModule} from './index';
2930

3031

@@ -539,6 +540,15 @@ describe('MatDatepicker', () => {
539540

540541
expect(inputEl.disabled).toBe(true);
541542
});
543+
544+
it('should disable toggle when form control disabled', () => {
545+
expect(testComponent.datepickerToggle.disabled).toBe(false);
546+
547+
testComponent.formControl.disable();
548+
fixture.detectChanges();
549+
550+
expect(testComponent.datepickerToggle.disabled).toBe(true);
551+
});
542552
});
543553

544554
describe('datepicker with mat-datepicker-toggle', () => {
@@ -582,7 +592,7 @@ describe('MatDatepicker', () => {
582592
});
583593

584594
it('should not open calendar when toggle clicked if input is disabled', () => {
585-
expect(testComponent.datepicker.disabled).toBeUndefined();
595+
expect(testComponent.datepicker.disabled).toBe(false);
586596

587597
testComponent.input.disabled = true;
588598
fixture.detectChanges();
@@ -1120,13 +1130,15 @@ class DatepickerWithNgModel {
11201130
@Component({
11211131
template: `
11221132
<input [formControl]="formControl" [matDatepicker]="d">
1133+
<mat-datepicker-toggle [for]="d"></mat-datepicker-toggle>
11231134
<mat-datepicker #d></mat-datepicker>
11241135
`,
11251136
})
11261137
class DatepickerWithFormControl {
11271138
formControl = new FormControl();
11281139
@ViewChild('d') datepicker: MatDatepicker<Date>;
11291140
@ViewChild(MatDatepickerInput) datepickerInput: MatDatepickerInput<Date>;
1141+
@ViewChild(MatDatepickerToggle) datepickerToggle: MatDatepickerToggle<Date>;
11301142
}
11311143

11321144

src/lib/datepicker/datepicker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export class MatDatepicker<D> implements OnDestroy {
149149
@Input()
150150
get disabled() {
151151
return this._disabled === undefined && this._datepickerInput ?
152-
this._datepickerInput.disabled : this._disabled;
152+
this._datepickerInput.disabled : !!this._disabled;
153153
}
154154
set disabled(value: any) {
155155
const newValue = coerceBooleanProperty(value);

0 commit comments

Comments
 (0)