Skip to content

Commit 99963c4

Browse files
devversionkara
authored andcommitted
feat(slider): emit input event when slider thumb moves (#2325)
Closes #2296
1 parent eec3108 commit 99963c4

File tree

2 files changed

+86
-9
lines changed

2 files changed

+86
-9
lines changed

src/lib/slider/slider.spec.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,55 @@ describe('MdSlider', () => {
785785
});
786786
});
787787

788+
describe('slider with input event', () => {
789+
let fixture: ComponentFixture<SliderWithChangeHandler>;
790+
let sliderDebugElement: DebugElement;
791+
let sliderNativeElement: HTMLElement;
792+
let sliderTrackElement: HTMLElement;
793+
let testComponent: SliderWithChangeHandler;
794+
795+
beforeEach(() => {
796+
fixture = TestBed.createComponent(SliderWithChangeHandler);
797+
fixture.detectChanges();
798+
799+
testComponent = fixture.debugElement.componentInstance;
800+
spyOn(testComponent, 'onInput');
801+
spyOn(testComponent, 'onChange');
802+
803+
sliderDebugElement = fixture.debugElement.query(By.directive(MdSlider));
804+
sliderNativeElement = sliderDebugElement.nativeElement;
805+
sliderTrackElement = <HTMLElement>sliderNativeElement.querySelector('.md-slider-track');
806+
});
807+
808+
it('should emit an input event while sliding', () => {
809+
expect(testComponent.onChange).not.toHaveBeenCalled();
810+
811+
dispatchMouseenterEvent(sliderNativeElement);
812+
dispatchSlideEvent(sliderNativeElement, 0.5, gestureConfig);
813+
dispatchSlideEvent(sliderNativeElement, 1, gestureConfig);
814+
dispatchSlideEndEvent(sliderNativeElement, 1, gestureConfig);
815+
816+
fixture.detectChanges();
817+
818+
// The input event should fire twice, because the slider changed two times.
819+
expect(testComponent.onInput).toHaveBeenCalledTimes(2);
820+
expect(testComponent.onChange).toHaveBeenCalledTimes(1);
821+
});
822+
823+
it('should emit an input event when clicking', () => {
824+
expect(testComponent.onChange).not.toHaveBeenCalled();
825+
826+
dispatchClickEventSequence(sliderNativeElement, 0.75);
827+
828+
fixture.detectChanges();
829+
830+
// The `onInput` event should be emitted once due to a single click.
831+
expect(testComponent.onInput).toHaveBeenCalledTimes(1);
832+
expect(testComponent.onChange).toHaveBeenCalledTimes(1);
833+
});
834+
835+
});
836+
788837
describe('keyboard support', () => {
789838
let fixture: ComponentFixture<StandardSlider>;
790839
let sliderDebugElement: DebugElement;
@@ -1134,11 +1183,12 @@ class SliderWithValueSmallerThanMin { }
11341183
class SliderWithValueGreaterThanMax { }
11351184

11361185
@Component({
1137-
template: `<md-slider (change)="onChange($event)"></md-slider>`,
1186+
template: `<md-slider (change)="onChange($event)" (input)="onInput($event)"></md-slider>`,
11381187
styles: [styles],
11391188
})
11401189
class SliderWithChangeHandler {
1141-
onChange() { }
1190+
onChange() { };
1191+
onInput() { };
11421192
}
11431193

11441194
@Component({

src/lib/slider/slider.ts

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,9 @@ export class MdSlider implements ControlValueAccessor {
117117

118118
private _controlValueAccessorChangeFn: (value: any) => void = () => {};
119119

120-
/** The last value for which a change event was emitted. */
121-
private _lastEmittedValue: number = null;
120+
/** The last values for which a change or input event was emitted. */
121+
private _lastChangeValue: number = null;
122+
private _lastInputValue: number = null;
122123

123124
/** onTouch function registered via registerOnTouch (ControlValueAccessor). */
124125
onTouched: () => any = () => {};
@@ -301,6 +302,9 @@ export class MdSlider implements ControlValueAccessor {
301302
/** Event emitted when the slider value has changed. */
302303
@Output() change = new EventEmitter<MdSliderChange>();
303304

305+
/** Event emitted when the slider thumb moves. */
306+
@Output() input = new EventEmitter<MdSliderChange>();
307+
304308
constructor(@Optional() private _dir: Dir, elementRef: ElementRef) {
305309
this._renderer = new SliderRenderer(elementRef);
306310
}
@@ -325,6 +329,9 @@ export class MdSlider implements ControlValueAccessor {
325329
this._isSliding = false;
326330
this._renderer.addFocus();
327331
this._updateValueFromPosition({x: event.clientX, y: event.clientY});
332+
333+
/* Emits a change and input event if the value changed. */
334+
this._emitInputEvent();
328335
this._emitValueIfChanged();
329336
}
330337

@@ -336,6 +343,9 @@ export class MdSlider implements ControlValueAccessor {
336343
// Prevent the slide from selecting anything else.
337344
event.preventDefault();
338345
this._updateValueFromPosition({x: event.center.x, y: event.center.y});
346+
347+
// Native range elements always emit `input` events when the value changed while sliding.
348+
this._emitInputEvent();
339349
}
340350

341351
_onSlideStart(event: HammerInput) {
@@ -439,16 +449,23 @@ export class MdSlider implements ControlValueAccessor {
439449

440450
/** Emits a change event if the current value is different from the last emitted value. */
441451
private _emitValueIfChanged() {
442-
if (this.value != this._lastEmittedValue) {
443-
let event = new MdSliderChange();
444-
event.source = this;
445-
event.value = this.value;
446-
this._lastEmittedValue = this.value;
452+
if (this.value != this._lastChangeValue) {
453+
let event = this._createChangeEvent();
454+
this._lastChangeValue = this.value;
447455
this._controlValueAccessorChangeFn(this.value);
448456
this.change.emit(event);
449457
}
450458
}
451459

460+
/** Emits an input event when the current value is different from the last emitted value. */
461+
private _emitInputEvent() {
462+
if (this.value != this._lastInputValue) {
463+
let event = this._createChangeEvent();
464+
this._lastInputValue = this.value;
465+
this.input.emit(event);
466+
}
467+
}
468+
452469
/** Updates the amount of space between ticks as a percentage of the width of the slider. */
453470
private _updateTickIntervalPercent() {
454471
if (!this.tickInterval) {
@@ -466,6 +483,16 @@ export class MdSlider implements ControlValueAccessor {
466483
}
467484
}
468485

486+
/** Creates a slider change object from the specified value. */
487+
private _createChangeEvent(value = this.value): MdSliderChange {
488+
let event = new MdSliderChange();
489+
490+
event.source = this;
491+
event.value = value;
492+
493+
return event;
494+
}
495+
469496
/** Calculates the percentage of the slider that a value is. */
470497
private _calculatePercentage(value: number) {
471498
return (value - this.min) / (this.max - this.min);

0 commit comments

Comments
 (0)