Skip to content

Commit 6a34f6f

Browse files
jelbournmmalerba
authored andcommitted
chore: add CanDisable mixin to checkbox, radio-group, slide-toggle, and (#4209)
slider
1 parent bd48f39 commit 6a34f6f

File tree

5 files changed

+64
-65
lines changed

5 files changed

+64
-65
lines changed

src/lib/button/button.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ export const _MdButtonMixinBase = mixinDisabled(MdButtonBase);
9797
host: {
9898
'[disabled]': 'disabled || null',
9999
},
100-
inputs: ['disabled'],
101100
templateUrl: 'button.html',
102101
styleUrls: ['button.css'],
102+
inputs: ['disabled'],
103103
encapsulation: ViewEncapsulation.None,
104104
changeDetection: ChangeDetectionStrategy.OnPush,
105105
})

src/lib/checkbox/checkbox.ts

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,22 @@
11
import {
2-
ChangeDetectorRef,
2+
AfterViewInit,
33
ChangeDetectionStrategy,
4+
ChangeDetectorRef,
45
Component,
56
ElementRef,
67
EventEmitter,
8+
forwardRef,
79
Input,
10+
OnDestroy,
811
Output,
912
Renderer,
10-
ViewEncapsulation,
11-
forwardRef,
1213
ViewChild,
13-
AfterViewInit,
14-
OnDestroy,
14+
ViewEncapsulation,
1515
} from '@angular/core';
16-
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';
16+
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
1717
import {coerceBooleanProperty} from '../core/coercion/boolean-property';
18-
import {
19-
MdRipple,
20-
RippleRef,
21-
FocusOriginMonitor,
22-
FocusOrigin,
23-
} from '../core';
18+
import {FocusOrigin, FocusOriginMonitor, MdRipple, RippleRef} from '../core';
19+
import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled';
2420

2521

2622
/** Monotonically increasing integer used to auto-generate unique ids for checkbox components. */
@@ -60,6 +56,11 @@ export class MdCheckboxChange {
6056
checked: boolean;
6157
}
6258

59+
// Boilerplate for applying mixins to MdCheckbox.
60+
export class MdCheckboxBase { }
61+
export const _MdCheckboxMixinBase = mixinDisabled(MdCheckboxBase);
62+
63+
6364
/**
6465
* A material design checkbox component. Supports all of the functionality of an HTML5 checkbox,
6566
* and exposes a similar API. A MdCheckbox can be either checked, unchecked, indeterminate, or
@@ -74,17 +75,19 @@ export class MdCheckboxChange {
7475
templateUrl: 'checkbox.html',
7576
styleUrls: ['checkbox.css'],
7677
host: {
77-
'[class.mat-checkbox]': 'true',
78+
'class': 'mat-checkbox',
7879
'[class.mat-checkbox-indeterminate]': 'indeterminate',
7980
'[class.mat-checkbox-checked]': 'checked',
8081
'[class.mat-checkbox-disabled]': 'disabled',
8182
'[class.mat-checkbox-label-before]': 'labelPosition == "before"',
8283
},
8384
providers: [MD_CHECKBOX_CONTROL_VALUE_ACCESSOR],
85+
inputs: ['disabled'],
8486
encapsulation: ViewEncapsulation.None,
8587
changeDetection: ChangeDetectionStrategy.OnPush
8688
})
87-
export class MdCheckbox implements ControlValueAccessor, AfterViewInit, OnDestroy {
89+
export class MdCheckbox extends _MdCheckboxMixinBase
90+
implements ControlValueAccessor, AfterViewInit, OnDestroy, CanDisable {
8891
/**
8992
* Attached to the aria-label attribute of the host element. In most cases, arial-labelledby will
9093
* take precedence so this may be omitted.
@@ -137,13 +140,6 @@ export class MdCheckbox implements ControlValueAccessor, AfterViewInit, OnDestro
137140
/** Whether the label should appear after or before the checkbox. Defaults to 'after' */
138141
@Input() labelPosition: 'before' | 'after' = 'after';
139142

140-
private _disabled: boolean = false;
141-
142-
/** Whether the checkbox is disabled. */
143-
@Input()
144-
get disabled(): boolean { return this._disabled; }
145-
set disabled(value) { this._disabled = coerceBooleanProperty(value); }
146-
147143
/** Tabindex value that is passed to the underlying input element. */
148144
@Input() tabIndex: number = 0;
149145

@@ -189,6 +185,7 @@ export class MdCheckbox implements ControlValueAccessor, AfterViewInit, OnDestro
189185
private _elementRef: ElementRef,
190186
private _changeDetectorRef: ChangeDetectorRef,
191187
private _focusOriginMonitor: FocusOriginMonitor) {
188+
super();
192189
this.color = 'accent';
193190
}
194191

src/lib/radio/radio.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
FocusOrigin,
2727
} from '../core';
2828
import {coerceBooleanProperty} from '../core/coercion/boolean-property';
29+
import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled';
2930

3031

3132
/**
@@ -49,6 +50,11 @@ export class MdRadioChange {
4950
value: any;
5051
}
5152

53+
54+
// Boilerplate for applying mixins to MdRadioGroup.
55+
export class MdRadioGroupBase { }
56+
export const _MdRadioGroupMixinBase = mixinDisabled(MdRadioGroupBase);
57+
5258
/**
5359
* A group of radio buttons. May contain one or more `<md-radio-button>` elements.
5460
*/
@@ -59,8 +65,10 @@ export class MdRadioChange {
5965
'role': 'radiogroup',
6066
'[class.mat-radio-group]': 'true',
6167
},
68+
inputs: ['disabled'],
6269
})
63-
export class MdRadioGroup implements AfterContentInit, ControlValueAccessor {
70+
export class MdRadioGroup extends _MdRadioGroupMixinBase
71+
implements AfterContentInit, ControlValueAccessor, CanDisable {
6472
/**
6573
* Selected value for group. Should equal the value of the selected radio button if there *is*
6674
* a corresponding radio button with a matching value. If there is *not* such a corresponding
@@ -72,9 +80,6 @@ export class MdRadioGroup implements AfterContentInit, ControlValueAccessor {
7280
/** The HTML name attribute applied to radio buttons in this group. */
7381
private _name: string = `md-radio-group-${_uniqueIdCounter++}`;
7482

75-
/** Disables all individual radio buttons assigned to this group. */
76-
private _disabled: boolean = false;
77-
7883
/** The currently selected radio button. Should match value. */
7984
private _selected: MdRadioButton = null;
8085

@@ -127,14 +132,6 @@ export class MdRadioGroup implements AfterContentInit, ControlValueAccessor {
127132
/** Whether the labels should appear after or before the radio-buttons. Defaults to 'after' */
128133
@Input() labelPosition: 'before' | 'after' = 'after';
129134

130-
/** Whether the radio button is disabled. */
131-
@Input()
132-
get disabled(): boolean { return this._disabled; }
133-
set disabled(value) {
134-
// The presence of *any* disabled value makes the component disabled, *except* for false.
135-
this._disabled = (value != null && value !== false) ? true : null;
136-
}
137-
138135
/** Value of the radio button. */
139136
@Input()
140137
get value(): any { return this._value; }
@@ -369,8 +366,7 @@ export class MdRadioButton implements OnInit, AfterViewInit, OnDestroy {
369366
}
370367

371368
set disabled(value: boolean) {
372-
// The presence of *any* disabled value makes the component disabled, *except* for false.
373-
this._disabled = (value != null && value !== false) ? true : null;
369+
this._disabled = coerceBooleanProperty(value);
374370
}
375371

376372
/**

src/lib/slide-toggle/slide-toggle.ts

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
11
import {
2+
AfterContentInit,
3+
ChangeDetectionStrategy,
24
Component,
35
ElementRef,
4-
Renderer,
6+
EventEmitter,
57
forwardRef,
6-
ChangeDetectionStrategy,
78
Input,
9+
OnDestroy,
810
Output,
9-
EventEmitter,
10-
AfterContentInit,
11+
Renderer,
1112
ViewChild,
12-
ViewEncapsulation,
13-
OnDestroy,
13+
ViewEncapsulation
1414
} from '@angular/core';
1515
import {
1616
applyCssTransform,
1717
coerceBooleanProperty,
18-
HammerInput,
19-
FocusOriginMonitor,
2018
FocusOrigin,
19+
FocusOriginMonitor,
20+
HammerInput,
2121
MdRipple,
2222
RippleRef
2323
} from '../core';
2424
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
25-
import {Observable} from 'rxjs/Observable';
25+
import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled';
26+
2627

2728
export const MD_SLIDE_TOGGLE_VALUE_ACCESSOR: any = {
2829
provide: NG_VALUE_ACCESSOR,
@@ -39,9 +40,13 @@ export class MdSlideToggleChange {
3940
// Increasing integer for generating unique ids for slide-toggle components.
4041
let nextId = 0;
4142

42-
/**
43-
* Two-state control, which can be also called `switch`.
44-
*/
43+
44+
45+
// Boilerplate for applying mixins to MdSlideToggle.
46+
export class MdSlideToggleBase { }
47+
export const _MdSlideToggleMixinBase = mixinDisabled(MdSlideToggleBase);
48+
49+
/** Represents a slidable "switch" toggle that can be moved between on and off. */
4550
@Component({
4651
moduleId: module.id,
4752
selector: 'md-slide-toggle, mat-slide-toggle',
@@ -54,11 +59,12 @@ let nextId = 0;
5459
templateUrl: 'slide-toggle.html',
5560
styleUrls: ['slide-toggle.css'],
5661
providers: [MD_SLIDE_TOGGLE_VALUE_ACCESSOR],
62+
inputs: ['disabled'],
5763
encapsulation: ViewEncapsulation.None,
5864
changeDetection: ChangeDetectionStrategy.OnPush
5965
})
60-
export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueAccessor {
61-
66+
export class MdSlideToggle extends _MdSlideToggleMixinBase
67+
implements OnDestroy, AfterContentInit, ControlValueAccessor, CanDisable {
6268
private onChange = (_: any) => {};
6369
private onTouched = () => {};
6470

@@ -67,7 +73,6 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA
6773
private _checked: boolean = false;
6874
private _color: string;
6975
private _slideRenderer: SlideToggleRenderer = null;
70-
private _disabled: boolean = false;
7176
private _required: boolean = false;
7277
private _disableRipple: boolean = false;
7378

@@ -92,11 +97,6 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA
9297
/** Used to set the aria-labelledby attribute on the underlying input element. */
9398
@Input('aria-labelledby') ariaLabelledby: string = null;
9499

95-
/** Whether the slide-toggle is disabled. */
96-
@Input()
97-
get disabled(): boolean { return this._disabled; }
98-
set disabled(value) { this._disabled = coerceBooleanProperty(value); }
99-
100100
/** Whether the slide-toggle is required. */
101101
@Input()
102102
get required(): boolean { return this._required; }
@@ -121,7 +121,9 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA
121121

122122
constructor(private _elementRef: ElementRef,
123123
private _renderer: Renderer,
124-
private _focusOriginMonitor: FocusOriginMonitor) {}
124+
private _focusOriginMonitor: FocusOriginMonitor) {
125+
super();
126+
}
125127

126128
ngAfterContentInit() {
127129
this._slideRenderer = new SlideToggleRenderer(this._elementRef);

src/lib/slider/slider.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {
2424
UP_ARROW
2525
} from '../core/keyboard/keycodes';
2626
import {FocusOrigin, FocusOriginMonitor} from '../core/style/focus-origin-monitor';
27+
import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled';
28+
2729

2830
/**
2931
* Visually, a 30px separation between tick marks looks best. This is very subjective but it is
@@ -59,6 +61,11 @@ export class MdSliderChange {
5961
value: number;
6062
}
6163

64+
65+
// Boilerplate for applying mixins to MdSlider.
66+
export class MdSliderBase { }
67+
export const _MdSliderMixinBase = mixinDisabled(MdSliderBase);
68+
6269
/**
6370
* Allows users to select from a range of values by moving the slider thumb. It is similar in
6471
* behavior to the native `<input type="range">` element.
@@ -68,7 +75,6 @@ export class MdSliderChange {
6875
selector: 'md-slider, mat-slider',
6976
providers: [MD_SLIDER_VALUE_ACCESSOR],
7077
host: {
71-
'[class.mat-slider]': 'true',
7278
'(focus)': '_onFocus()',
7379
'(blur)': '_onBlur()',
7480
'(click)': '_onClick($event)',
@@ -78,6 +84,7 @@ export class MdSliderChange {
7884
'(slide)': '_onSlide($event)',
7985
'(slideend)': '_onSlideEnd()',
8086
'(slidestart)': '_onSlideStart($event)',
87+
'class': 'mat-slider',
8188
'role': 'slider',
8289
'tabindex': '0',
8390
'[attr.aria-disabled]': 'disabled',
@@ -99,15 +106,11 @@ export class MdSliderChange {
99106
},
100107
templateUrl: 'slider.html',
101108
styleUrls: ['slider.css'],
109+
inputs: ['disabled'],
102110
encapsulation: ViewEncapsulation.None,
103111
})
104-
export class MdSlider implements ControlValueAccessor, OnDestroy {
105-
/** Whether or not the slider is disabled. */
106-
@Input()
107-
get disabled(): boolean { return this._disabled; }
108-
set disabled(value) { this._disabled = coerceBooleanProperty(value); }
109-
private _disabled: boolean = false;
110-
112+
export class MdSlider extends _MdSliderMixinBase
113+
implements ControlValueAccessor, OnDestroy, CanDisable {
111114
/** Whether the slider is inverted. */
112115
@Input()
113116
get invert() { return this._invert; }
@@ -379,6 +382,7 @@ export class MdSlider implements ControlValueAccessor, OnDestroy {
379382

380383
constructor(renderer: Renderer, private _elementRef: ElementRef,
381384
private _focusOriginMonitor: FocusOriginMonitor, @Optional() private _dir: Dir) {
385+
super();
382386
this._focusOriginMonitor.monitor(this._elementRef.nativeElement, renderer, true)
383387
.subscribe((origin: FocusOrigin) => this._isActive = !!origin && origin !== 'keyboard');
384388
this._renderer = new SliderRenderer(this._elementRef);

0 commit comments

Comments
 (0)