-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add two way binding to slider #1029
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,13 @@ import { | |
Input, | ||
ViewEncapsulation, | ||
AfterContentInit, | ||
forwardRef, | ||
} from '@angular/core'; | ||
import { | ||
NG_VALUE_ACCESSOR, | ||
ControlValueAccessor, | ||
FormsModule, | ||
} from '@angular/forms'; | ||
import {HAMMER_GESTURE_CONFIG} from '@angular/platform-browser'; | ||
import {BooleanFieldValue} from '@angular2-material/core/annotations/field-value'; | ||
import {applyCssTransform} from '@angular2-material/core/style/apply-transform'; | ||
|
@@ -18,9 +24,20 @@ import {MdGestureConfig} from '@angular2-material/core/core'; | |
*/ | ||
const MIN_AUTO_TICK_SEPARATION = 30; | ||
|
||
/** | ||
* Provider Expression that allows md-slider to register as a ControlValueAccessor. | ||
* This allows it to support [(ngModel)] and [formControl]. | ||
*/ | ||
export const MD_SLIDER_VALUE_ACCESSOR: any = { | ||
provide: NG_VALUE_ACCESSOR, | ||
useExisting: forwardRef(() => MdSlider), | ||
multi: true | ||
}; | ||
|
||
@Component({ | ||
moduleId: module.id, | ||
selector: 'md-slider', | ||
providers: [MD_SLIDER_VALUE_ACCESSOR], | ||
host: { | ||
'tabindex': '0', | ||
'(click)': 'onClick($event)', | ||
|
@@ -34,7 +51,7 @@ const MIN_AUTO_TICK_SEPARATION = 30; | |
styleUrls: ['slider.css'], | ||
encapsulation: ViewEncapsulation.None, | ||
}) | ||
export class MdSlider implements AfterContentInit { | ||
export class MdSlider implements AfterContentInit, ControlValueAccessor { | ||
/** A renderer to handle updating the slider's thumb and fill track. */ | ||
private _renderer: SliderRenderer = null; | ||
|
||
|
@@ -61,6 +78,11 @@ export class MdSlider implements AfterContentInit { | |
/** The percentage of the slider that coincides with the value. */ | ||
private _percent: number = 0; | ||
|
||
private _controlValueAccessorChangeFn: (value: any) => void = (value) => {}; | ||
|
||
/** onTouch function registered via registerOnTouch (ControlValueAccessor). */ | ||
onTouched: () => any = () => {}; | ||
|
||
/** The values at which the thumb will snap. */ | ||
@Input() step: number = 1; | ||
|
||
|
@@ -123,8 +145,15 @@ export class MdSlider implements AfterContentInit { | |
} | ||
|
||
set value(v: number) { | ||
// Only set the value to a valid number. v is casted to an any as we know it will come in as a | ||
// string but it is labeled as a number which causes parseFloat to not accept it. | ||
if (isNaN(parseFloat(<any> v))) { | ||
return; | ||
} | ||
|
||
this._value = Number(v); | ||
this._isInitialized = true; | ||
this._controlValueAccessorChangeFn(this._value); | ||
} | ||
|
||
constructor(elementRef: ElementRef) { | ||
|
@@ -138,7 +167,10 @@ export class MdSlider implements AfterContentInit { | |
*/ | ||
ngAfterContentInit() { | ||
this._sliderDimensions = this._renderer.getSliderDimensions(); | ||
this.snapToValue(); | ||
// This needs to be called after content init because the value can be set to the min if the | ||
// value itself isn't set. If this happens, the control value accessor needs to be updated. | ||
this._controlValueAccessorChangeFn(this.value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add comment explaining why this is necessary |
||
this.snapThumbToValue(); | ||
this._updateTickSeparation(); | ||
} | ||
|
||
|
@@ -152,7 +184,7 @@ export class MdSlider implements AfterContentInit { | |
this.isSliding = false; | ||
this._renderer.addFocus(); | ||
this.updateValueFromPosition(event.clientX); | ||
this.snapToValue(); | ||
this.snapThumbToValue(); | ||
} | ||
|
||
/** TODO: internal */ | ||
|
@@ -182,7 +214,7 @@ export class MdSlider implements AfterContentInit { | |
/** TODO: internal */ | ||
onSlideEnd() { | ||
this.isSliding = false; | ||
this.snapToValue(); | ||
this.snapThumbToValue(); | ||
} | ||
|
||
/** TODO: internal */ | ||
|
@@ -196,6 +228,7 @@ export class MdSlider implements AfterContentInit { | |
/** TODO: internal */ | ||
onBlur() { | ||
this.isActive = false; | ||
this.onTouched(); | ||
} | ||
|
||
/** | ||
|
@@ -230,7 +263,7 @@ export class MdSlider implements AfterContentInit { | |
* Snaps the thumb to the current value. | ||
* Called after a click or drag event is over. | ||
*/ | ||
snapToValue() { | ||
snapThumbToValue() { | ||
this.updatePercentFromValue(); | ||
this._renderer.updateThumbAndFillPosition(this._percent, this._sliderDimensions.width); | ||
} | ||
|
@@ -315,6 +348,34 @@ export class MdSlider implements AfterContentInit { | |
clamp(value: number, min = 0, max = 1) { | ||
return Math.max(min, Math.min(value, max)); | ||
} | ||
|
||
/** | ||
* Implemented as part of ControlValueAccessor. | ||
* TODO: internal | ||
*/ | ||
writeValue(value: any) { | ||
this.value = value; | ||
|
||
if (this._sliderDimensions) { | ||
this.snapThumbToValue(); | ||
} | ||
} | ||
|
||
/** | ||
* Implemented as part of ControlValueAccessor. | ||
* TODO: internal | ||
*/ | ||
registerOnChange(fn: (value: any) => void) { | ||
this._controlValueAccessorChangeFn = fn; | ||
} | ||
|
||
/** | ||
* Implemented as part of ControlValueAccessor. | ||
* TODO: internal | ||
*/ | ||
registerOnTouched(fn: any) { | ||
this.onTouched = fn; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where are you calling this? It doesn't look like the onBlur function calls it. Have you checked that the control is correctly set as touched? |
||
} | ||
} | ||
|
||
/** | ||
|
@@ -392,6 +453,7 @@ export const MD_SLIDER_DIRECTIVES = [MdSlider]; | |
|
||
|
||
@NgModule({ | ||
imports: [FormsModule], | ||
exports: MD_SLIDER_DIRECTIVES, | ||
declarations: MD_SLIDER_DIRECTIVES, | ||
providers: [ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,29 @@ | ||
<h1>Default Slider</h1> | ||
<section class="demo-section"> | ||
Label <md-slider #slidey></md-slider> | ||
{{slidey.value}} | ||
</section> | ||
Label <md-slider #slidey></md-slider> | ||
{{slidey.value}} | ||
|
||
<h1>Slider with Min and Max</h1> | ||
<section class="demo-section"> | ||
<md-slider min="5" max="7" #slider2></md-slider> | ||
{{slider2.value}} | ||
</section> | ||
<md-slider min="5" max="7" #slider2></md-slider> | ||
{{slider2.value}} | ||
|
||
<h1>Disabled Slider</h1> | ||
<section class="demo-section"> | ||
<md-slider disabled #slider3></md-slider> | ||
{{slider3.value}} | ||
</section> | ||
<md-slider disabled #slider3></md-slider> | ||
{{slider3.value}} | ||
|
||
<h1>Slider with set value</h1> | ||
<section class="demo-section"> | ||
<md-slider value="43" #slider4></md-slider> | ||
</section> | ||
<md-slider value="43"></md-slider> | ||
|
||
<h1>Slider with step defined</h1> | ||
<section class="demo-section"> | ||
<md-slider min="1" max="100" step="20" #slider5></md-slider> | ||
{{slider5.value}} | ||
</section> | ||
<md-slider min="1" max="100" step="20" #slider5></md-slider> | ||
{{slider5.value}} | ||
|
||
<h1>Slider with set tick interval</h1> | ||
<md-slider tick-interval="auto"></md-slider> | ||
<md-slider tick-interval="9"></md-slider> | ||
|
||
<h1>Slider with Thumb Label</h1> | ||
<md-slider thumb-label></md-slider> | ||
|
||
<h1>Slider with two-way binding</h1> | ||
<md-slider [(ngModel)]="demo" step="40"></md-slider> | ||
<input [(ngModel)]="demo"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make import indent consistent in this file