@@ -84,9 +84,9 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase implements OnDestroy,
8484 private onTouched = ( ) => { } ;
8585
8686 private _uniqueId : string = `md-slide-toggle-${ ++ nextUniqueId } ` ;
87- private _checked : boolean = false ;
8887 private _slideRenderer : SlideToggleRenderer ;
8988 private _required : boolean = false ;
89+ private _checked : boolean = false ;
9090
9191 /** Reference to the focus state ripple. */
9292 private _focusRipple : RippleRef | null ;
@@ -103,6 +103,8 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase implements OnDestroy,
103103 /** Whether the label should appear after or before the slide-toggle. Defaults to 'after' */
104104 @Input ( ) labelPosition : 'before' | 'after' = 'after' ;
105105
106+ /** Whether the slide-toggle element is checked or not */
107+
106108 /** Used to set the aria-label attribute on the underlying input element. */
107109 @Input ( 'aria-label' ) ariaLabel : string | null = null ;
108110
@@ -114,6 +116,13 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase implements OnDestroy,
114116 get required ( ) : boolean { return this . _required ; }
115117 set required ( value ) { this . _required = coerceBooleanProperty ( value ) ; }
116118
119+ /** Whether the slide-toggle element is checked or not */
120+ @Input ( )
121+ get checked ( ) : boolean { return this . _checked ; }
122+ set checked ( value ) {
123+ this . _checked = ! ! value ;
124+ this . _changeDetectorRef . markForCheck ( ) ;
125+ }
117126 /** An event will be dispatched each time the slide-toggle changes its value. */
118127 @Output ( ) change : EventEmitter < MdSlideToggleChange > = new EventEmitter < MdSlideToggleChange > ( ) ;
119128
@@ -147,29 +156,30 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase implements OnDestroy,
147156 }
148157
149158 /**
150- * The onChangeEvent method will be also called on click.
151- * This is because everything for the slide-toggle is wrapped inside of a label,
152- * which triggers a onChange event on click.
159+ * This function will called if the underlying input changed its value through user interaction.
153160 */
154161 _onChangeEvent ( event : Event ) {
155162 // We always have to stop propagation on the change event.
156163 // Otherwise the change event, from the input element, will bubble up and
157164 // emit its event object to the component's `change` output.
158165 event . stopPropagation ( ) ;
159166
160- // Once a drag is currently in progress, we do not want to toggle the slide-toggle on a click.
161- if ( ! this . disabled && ! this . _slideRenderer . dragging ) {
162- this . toggle ( ) ;
167+ // Sync the value from the underlying input element with the slide-toggle component.
168+ this . checked = this . _inputElement . nativeElement . checked ;
163169
164- // Emit our custom change event if the native input emitted one.
165- // It is important to only emit it, if the native input triggered one, because
166- // we don't want to trigger a change event, when the `checked` variable changes for example.
167- this . _emitChangeEvent ( ) ;
168- }
170+ // Emit our custom change event if the native input emitted one.
171+ // It is important to only emit it, if the native input triggered one, because we don't want
172+ // to trigger a change event, when the `checked` variable changes programmatically.
173+ this . _emitChangeEvent ( ) ;
169174 }
170175
171176 _onInputClick ( event : Event ) {
172- this . onTouched ( ) ;
177+ // In some situations the user will release the mouse on the label element. The label element
178+ // redirects the click to the underlying input element and will result in a value change.
179+ // Prevent the default behavior if dragging, because the value will be set after drag.
180+ if ( this . _slideRenderer . dragging ) {
181+ event . preventDefault ( ) ;
182+ }
173183
174184 // We have to stop propagation for click events on the visual hidden input element.
175185 // By default, when a user clicks on a label element, a generated click event will be
@@ -183,7 +193,7 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase implements OnDestroy,
183193
184194 /** Implemented as part of ControlValueAccessor. */
185195 writeValue ( value : any ) : void {
186- this . checked = value ;
196+ this . checked = ! ! value ;
187197 }
188198
189199 /** Implemented as part of ControlValueAccessor. */
@@ -207,16 +217,6 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase implements OnDestroy,
207217 this . _focusOriginMonitor . focusVia ( this . _inputElement . nativeElement , 'keyboard' ) ;
208218 }
209219
210- /** Whether the slide-toggle is checked. */
211- @Input ( )
212- get checked ( ) { return ! ! this . _checked ; }
213- set checked ( value ) {
214- if ( this . checked !== ! ! value ) {
215- this . _checked = value ;
216- this . onChange ( this . _checked ) ;
217- }
218- }
219-
220220 /** Toggles the checked state of the slide-toggle. */
221221 toggle ( ) {
222222 this . checked = ! this . checked ;
@@ -238,15 +238,17 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase implements OnDestroy,
238238 }
239239 }
240240
241- /** Emits the change event to the `change` output EventEmitter */
241+ /**
242+ * Emits a change event on the `change` output. Also notifies the FormControl about the change.
243+ */
242244 private _emitChangeEvent ( ) {
243245 let event = new MdSlideToggleChange ( ) ;
244246 event . source = this ;
245247 event . checked = this . checked ;
246248 this . change . emit ( event ) ;
249+ this . onChange ( this . checked ) ;
247250 }
248251
249-
250252 _onDragStart ( ) {
251253 if ( ! this . disabled ) {
252254 this . _slideRenderer . startThumbDrag ( this . checked ) ;
0 commit comments