diff --git a/src/lib/button/button.ts b/src/lib/button/button.ts index 9f37877dfcd5..dd7ae4f8df39 100644 --- a/src/lib/button/button.ts +++ b/src/lib/button/button.ts @@ -97,9 +97,9 @@ export const _MdButtonMixinBase = mixinDisabled(MdButtonBase); host: { '[disabled]': 'disabled || null', }, - inputs: ['disabled'], templateUrl: 'button.html', styleUrls: ['button.css'], + inputs: ['disabled'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, }) diff --git a/src/lib/checkbox/checkbox.ts b/src/lib/checkbox/checkbox.ts index 0bc2259a3b9f..995cc57325a5 100644 --- a/src/lib/checkbox/checkbox.ts +++ b/src/lib/checkbox/checkbox.ts @@ -1,26 +1,22 @@ import { - ChangeDetectorRef, + AfterViewInit, ChangeDetectionStrategy, + ChangeDetectorRef, Component, ElementRef, EventEmitter, + forwardRef, Input, + OnDestroy, Output, Renderer, - ViewEncapsulation, - forwardRef, ViewChild, - AfterViewInit, - OnDestroy, + ViewEncapsulation, } from '@angular/core'; -import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms'; +import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; import {coerceBooleanProperty} from '../core/coercion/boolean-property'; -import { - MdRipple, - RippleRef, - FocusOriginMonitor, - FocusOrigin, -} from '../core'; +import {FocusOrigin, FocusOriginMonitor, MdRipple, RippleRef} from '../core'; +import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled'; /** Monotonically increasing integer used to auto-generate unique ids for checkbox components. */ @@ -60,6 +56,11 @@ export class MdCheckboxChange { checked: boolean; } +// Boilerplate for applying mixins to MdCheckbox. +export class MdCheckboxBase { } +export const _MdCheckboxMixinBase = mixinDisabled(MdCheckboxBase); + + /** * A material design checkbox component. Supports all of the functionality of an HTML5 checkbox, * and exposes a similar API. A MdCheckbox can be either checked, unchecked, indeterminate, or @@ -74,17 +75,19 @@ export class MdCheckboxChange { templateUrl: 'checkbox.html', styleUrls: ['checkbox.css'], host: { - '[class.mat-checkbox]': 'true', + 'class': 'mat-checkbox', '[class.mat-checkbox-indeterminate]': 'indeterminate', '[class.mat-checkbox-checked]': 'checked', '[class.mat-checkbox-disabled]': 'disabled', '[class.mat-checkbox-label-before]': 'labelPosition == "before"', }, providers: [MD_CHECKBOX_CONTROL_VALUE_ACCESSOR], + inputs: ['disabled'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush }) -export class MdCheckbox implements ControlValueAccessor, AfterViewInit, OnDestroy { +export class MdCheckbox extends _MdCheckboxMixinBase + implements ControlValueAccessor, AfterViewInit, OnDestroy, CanDisable { /** * Attached to the aria-label attribute of the host element. In most cases, arial-labelledby will * take precedence so this may be omitted. @@ -137,13 +140,6 @@ export class MdCheckbox implements ControlValueAccessor, AfterViewInit, OnDestro /** Whether the label should appear after or before the checkbox. Defaults to 'after' */ @Input() labelPosition: 'before' | 'after' = 'after'; - private _disabled: boolean = false; - - /** Whether the checkbox is disabled. */ - @Input() - get disabled(): boolean { return this._disabled; } - set disabled(value) { this._disabled = coerceBooleanProperty(value); } - /** Tabindex value that is passed to the underlying input element. */ @Input() tabIndex: number = 0; @@ -189,6 +185,7 @@ export class MdCheckbox implements ControlValueAccessor, AfterViewInit, OnDestro private _elementRef: ElementRef, private _changeDetectorRef: ChangeDetectorRef, private _focusOriginMonitor: FocusOriginMonitor) { + super(); this.color = 'accent'; } diff --git a/src/lib/radio/radio.ts b/src/lib/radio/radio.ts index a325102f26c9..0491bff81195 100644 --- a/src/lib/radio/radio.ts +++ b/src/lib/radio/radio.ts @@ -26,6 +26,7 @@ import { FocusOrigin, } from '../core'; import {coerceBooleanProperty} from '../core/coercion/boolean-property'; +import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled'; /** @@ -49,6 +50,11 @@ export class MdRadioChange { value: any; } + +// Boilerplate for applying mixins to MdRadioGroup. +export class MdRadioGroupBase { } +export const _MdRadioGroupMixinBase = mixinDisabled(MdRadioGroupBase); + /** * A group of radio buttons. May contain one or more `` elements. */ @@ -59,8 +65,10 @@ export class MdRadioChange { 'role': 'radiogroup', '[class.mat-radio-group]': 'true', }, + inputs: ['disabled'], }) -export class MdRadioGroup implements AfterContentInit, ControlValueAccessor { +export class MdRadioGroup extends _MdRadioGroupMixinBase + implements AfterContentInit, ControlValueAccessor, CanDisable { /** * Selected value for group. Should equal the value of the selected radio button if there *is* * 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 { /** The HTML name attribute applied to radio buttons in this group. */ private _name: string = `md-radio-group-${_uniqueIdCounter++}`; - /** Disables all individual radio buttons assigned to this group. */ - private _disabled: boolean = false; - /** The currently selected radio button. Should match value. */ private _selected: MdRadioButton = null; @@ -127,14 +132,6 @@ export class MdRadioGroup implements AfterContentInit, ControlValueAccessor { /** Whether the labels should appear after or before the radio-buttons. Defaults to 'after' */ @Input() labelPosition: 'before' | 'after' = 'after'; - /** Whether the radio button is disabled. */ - @Input() - get disabled(): boolean { return this._disabled; } - set disabled(value) { - // The presence of *any* disabled value makes the component disabled, *except* for false. - this._disabled = (value != null && value !== false) ? true : null; - } - /** Value of the radio button. */ @Input() get value(): any { return this._value; } @@ -369,8 +366,7 @@ export class MdRadioButton implements OnInit, AfterViewInit, OnDestroy { } set disabled(value: boolean) { - // The presence of *any* disabled value makes the component disabled, *except* for false. - this._disabled = (value != null && value !== false) ? true : null; + this._disabled = coerceBooleanProperty(value); } /** diff --git a/src/lib/slide-toggle/slide-toggle.ts b/src/lib/slide-toggle/slide-toggle.ts index 7eb8e9387484..13ae686b28b0 100644 --- a/src/lib/slide-toggle/slide-toggle.ts +++ b/src/lib/slide-toggle/slide-toggle.ts @@ -1,28 +1,29 @@ import { + AfterContentInit, + ChangeDetectionStrategy, Component, ElementRef, - Renderer, + EventEmitter, forwardRef, - ChangeDetectionStrategy, Input, + OnDestroy, Output, - EventEmitter, - AfterContentInit, + Renderer, ViewChild, - ViewEncapsulation, - OnDestroy, + ViewEncapsulation } from '@angular/core'; import { applyCssTransform, coerceBooleanProperty, - HammerInput, - FocusOriginMonitor, FocusOrigin, + FocusOriginMonitor, + HammerInput, MdRipple, RippleRef } from '../core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; -import {Observable} from 'rxjs/Observable'; +import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled'; + export const MD_SLIDE_TOGGLE_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, @@ -39,9 +40,13 @@ export class MdSlideToggleChange { // Increasing integer for generating unique ids for slide-toggle components. let nextId = 0; -/** - * Two-state control, which can be also called `switch`. - */ + + +// Boilerplate for applying mixins to MdSlideToggle. +export class MdSlideToggleBase { } +export const _MdSlideToggleMixinBase = mixinDisabled(MdSlideToggleBase); + +/** Represents a slidable "switch" toggle that can be moved between on and off. */ @Component({ moduleId: module.id, selector: 'md-slide-toggle, mat-slide-toggle', @@ -54,11 +59,12 @@ let nextId = 0; templateUrl: 'slide-toggle.html', styleUrls: ['slide-toggle.css'], providers: [MD_SLIDE_TOGGLE_VALUE_ACCESSOR], + inputs: ['disabled'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush }) -export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueAccessor { - +export class MdSlideToggle extends _MdSlideToggleMixinBase + implements OnDestroy, AfterContentInit, ControlValueAccessor, CanDisable { private onChange = (_: any) => {}; private onTouched = () => {}; @@ -67,7 +73,6 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA private _checked: boolean = false; private _color: string; private _slideRenderer: SlideToggleRenderer = null; - private _disabled: boolean = false; private _required: boolean = false; private _disableRipple: boolean = false; @@ -92,11 +97,6 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA /** Used to set the aria-labelledby attribute on the underlying input element. */ @Input('aria-labelledby') ariaLabelledby: string = null; - /** Whether the slide-toggle is disabled. */ - @Input() - get disabled(): boolean { return this._disabled; } - set disabled(value) { this._disabled = coerceBooleanProperty(value); } - /** Whether the slide-toggle is required. */ @Input() get required(): boolean { return this._required; } @@ -121,7 +121,9 @@ export class MdSlideToggle implements OnDestroy, AfterContentInit, ControlValueA constructor(private _elementRef: ElementRef, private _renderer: Renderer, - private _focusOriginMonitor: FocusOriginMonitor) {} + private _focusOriginMonitor: FocusOriginMonitor) { + super(); + } ngAfterContentInit() { this._slideRenderer = new SlideToggleRenderer(this._elementRef); diff --git a/src/lib/slider/slider.ts b/src/lib/slider/slider.ts index e0c374c97116..8773e88e1a0c 100644 --- a/src/lib/slider/slider.ts +++ b/src/lib/slider/slider.ts @@ -24,6 +24,8 @@ import { UP_ARROW } from '../core/keyboard/keycodes'; import {FocusOrigin, FocusOriginMonitor} from '../core/style/focus-origin-monitor'; +import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled'; + /** * Visually, a 30px separation between tick marks looks best. This is very subjective but it is @@ -59,6 +61,11 @@ export class MdSliderChange { value: number; } + +// Boilerplate for applying mixins to MdSlider. +export class MdSliderBase { } +export const _MdSliderMixinBase = mixinDisabled(MdSliderBase); + /** * Allows users to select from a range of values by moving the slider thumb. It is similar in * behavior to the native `` element. @@ -68,7 +75,6 @@ export class MdSliderChange { selector: 'md-slider, mat-slider', providers: [MD_SLIDER_VALUE_ACCESSOR], host: { - '[class.mat-slider]': 'true', '(focus)': '_onFocus()', '(blur)': '_onBlur()', '(click)': '_onClick($event)', @@ -78,6 +84,7 @@ export class MdSliderChange { '(slide)': '_onSlide($event)', '(slideend)': '_onSlideEnd()', '(slidestart)': '_onSlideStart($event)', + 'class': 'mat-slider', 'role': 'slider', 'tabindex': '0', '[attr.aria-disabled]': 'disabled', @@ -99,15 +106,11 @@ export class MdSliderChange { }, templateUrl: 'slider.html', styleUrls: ['slider.css'], + inputs: ['disabled'], encapsulation: ViewEncapsulation.None, }) -export class MdSlider implements ControlValueAccessor, OnDestroy { - /** Whether or not the slider is disabled. */ - @Input() - get disabled(): boolean { return this._disabled; } - set disabled(value) { this._disabled = coerceBooleanProperty(value); } - private _disabled: boolean = false; - +export class MdSlider extends _MdSliderMixinBase + implements ControlValueAccessor, OnDestroy, CanDisable { /** Whether the slider is inverted. */ @Input() get invert() { return this._invert; } @@ -379,6 +382,7 @@ export class MdSlider implements ControlValueAccessor, OnDestroy { constructor(renderer: Renderer, private _elementRef: ElementRef, private _focusOriginMonitor: FocusOriginMonitor, @Optional() private _dir: Dir) { + super(); this._focusOriginMonitor.monitor(this._elementRef.nativeElement, renderer, true) .subscribe((origin: FocusOrigin) => this._isActive = !!origin && origin !== 'keyboard'); this._renderer = new SliderRenderer(this._elementRef);