@@ -6,7 +6,13 @@ import {
66 Input ,
77 ViewEncapsulation ,
88 AfterContentInit ,
9+ forwardRef ,
910} from '@angular/core' ;
11+ import {
12+ NG_VALUE_ACCESSOR ,
13+ ControlValueAccessor ,
14+ FormsModule ,
15+ } from '@angular/forms' ;
1016import { HAMMER_GESTURE_CONFIG } from '@angular/platform-browser' ;
1117import { BooleanFieldValue } from '@angular2-material/core/annotations/field-value' ;
1218import { applyCssTransform } from '@angular2-material/core/style/apply-transform' ;
@@ -18,9 +24,20 @@ import {MdGestureConfig} from '@angular2-material/core/core';
1824 */
1925const MIN_AUTO_TICK_SEPARATION = 30 ;
2026
27+ /**
28+ * Provider Expression that allows md-slider to register as a ControlValueAccessor.
29+ * This allows it to support [(ngModel)] and [formControl].
30+ */
31+ export const MD_SLIDER_VALUE_ACCESSOR : any = {
32+ provide : NG_VALUE_ACCESSOR ,
33+ useExisting : forwardRef ( ( ) => MdSlider ) ,
34+ multi : true
35+ } ;
36+
2137@Component ( {
2238 moduleId : module . id ,
2339 selector : 'md-slider' ,
40+ providers : [ MD_SLIDER_VALUE_ACCESSOR ] ,
2441 host : {
2542 'tabindex' : '0' ,
2643 '(click)' : 'onClick($event)' ,
@@ -34,7 +51,7 @@ const MIN_AUTO_TICK_SEPARATION = 30;
3451 styleUrls : [ 'slider.css' ] ,
3552 encapsulation : ViewEncapsulation . None ,
3653} )
37- export class MdSlider implements AfterContentInit {
54+ export class MdSlider implements AfterContentInit , ControlValueAccessor {
3855 /** A renderer to handle updating the slider's thumb and fill track. */
3956 private _renderer : SliderRenderer = null ;
4057
@@ -61,6 +78,11 @@ export class MdSlider implements AfterContentInit {
6178 /** The percentage of the slider that coincides with the value. */
6279 private _percent : number = 0 ;
6380
81+ private _controlValueAccessorChangeFn : ( value : any ) => void = ( value ) => { } ;
82+
83+ /** onTouch function registered via registerOnTouch (ControlValueAccessor). */
84+ onTouched : ( ) => any = ( ) => { } ;
85+
6486 /** The values at which the thumb will snap. */
6587 @Input ( ) step : number = 1 ;
6688
@@ -123,8 +145,15 @@ export class MdSlider implements AfterContentInit {
123145 }
124146
125147 set value ( v : number ) {
148+ // Only set the value to a valid number. v is casted to an any as we know it will come in as a
149+ // string but it is labeled as a number which causes parseFloat to not accept it.
150+ if ( isNaN ( parseFloat ( < any > v ) ) ) {
151+ return ;
152+ }
153+
126154 this . _value = Number ( v ) ;
127155 this . _isInitialized = true ;
156+ this . _controlValueAccessorChangeFn ( this . _value ) ;
128157 }
129158
130159 constructor ( elementRef : ElementRef ) {
@@ -138,7 +167,10 @@ export class MdSlider implements AfterContentInit {
138167 */
139168 ngAfterContentInit ( ) {
140169 this . _sliderDimensions = this . _renderer . getSliderDimensions ( ) ;
141- this . snapToValue ( ) ;
170+ // This needs to be called after content init because the value can be set to the min if the
171+ // value itself isn't set. If this happens, the control value accessor needs to be updated.
172+ this . _controlValueAccessorChangeFn ( this . value ) ;
173+ this . snapThumbToValue ( ) ;
142174 this . _updateTickSeparation ( ) ;
143175 }
144176
@@ -152,7 +184,7 @@ export class MdSlider implements AfterContentInit {
152184 this . isSliding = false ;
153185 this . _renderer . addFocus ( ) ;
154186 this . updateValueFromPosition ( event . clientX ) ;
155- this . snapToValue ( ) ;
187+ this . snapThumbToValue ( ) ;
156188 }
157189
158190 /** TODO: internal */
@@ -182,7 +214,7 @@ export class MdSlider implements AfterContentInit {
182214 /** TODO: internal */
183215 onSlideEnd ( ) {
184216 this . isSliding = false ;
185- this . snapToValue ( ) ;
217+ this . snapThumbToValue ( ) ;
186218 }
187219
188220 /** TODO: internal */
@@ -196,6 +228,7 @@ export class MdSlider implements AfterContentInit {
196228 /** TODO: internal */
197229 onBlur ( ) {
198230 this . isActive = false ;
231+ this . onTouched ( ) ;
199232 }
200233
201234 /**
@@ -230,7 +263,7 @@ export class MdSlider implements AfterContentInit {
230263 * Snaps the thumb to the current value.
231264 * Called after a click or drag event is over.
232265 */
233- snapToValue ( ) {
266+ snapThumbToValue ( ) {
234267 this . updatePercentFromValue ( ) ;
235268 this . _renderer . updateThumbAndFillPosition ( this . _percent , this . _sliderDimensions . width ) ;
236269 }
@@ -315,6 +348,34 @@ export class MdSlider implements AfterContentInit {
315348 clamp ( value : number , min = 0 , max = 1 ) {
316349 return Math . max ( min , Math . min ( value , max ) ) ;
317350 }
351+
352+ /**
353+ * Implemented as part of ControlValueAccessor.
354+ * TODO: internal
355+ */
356+ writeValue ( value : any ) {
357+ this . value = value ;
358+
359+ if ( this . _sliderDimensions ) {
360+ this . snapThumbToValue ( ) ;
361+ }
362+ }
363+
364+ /**
365+ * Implemented as part of ControlValueAccessor.
366+ * TODO: internal
367+ */
368+ registerOnChange ( fn : ( value : any ) => void ) {
369+ this . _controlValueAccessorChangeFn = fn ;
370+ }
371+
372+ /**
373+ * Implemented as part of ControlValueAccessor.
374+ * TODO: internal
375+ */
376+ registerOnTouched ( fn : any ) {
377+ this . onTouched = fn ;
378+ }
318379}
319380
320381/**
@@ -392,6 +453,7 @@ export const MD_SLIDER_DIRECTIVES = [MdSlider];
392453
393454
394455@NgModule ( {
456+ imports : [ FormsModule ] ,
395457 exports : MD_SLIDER_DIRECTIVES ,
396458 declarations : MD_SLIDER_DIRECTIVES ,
397459 providers : [
0 commit comments