Skip to content

Commit 9d3c405

Browse files
mmalerbatinayuangao
authored andcommitted
fix(slider): fix change & input emit logic. (#6234)
1 parent 2af284c commit 9d3c405

File tree

2 files changed

+59
-26
lines changed

2 files changed

+59
-26
lines changed

src/lib/slider/slider.spec.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
22
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
3-
import {Component, DebugElement} from '@angular/core';
3+
import {Component, DebugElement, ViewChild} from '@angular/core';
44
import {By, HAMMER_GESTURE_CONFIG} from '@angular/platform-browser';
55
import {MdSlider, MdSliderModule} from './index';
66
import {TestGestureConfig} from './test-gesture-config';
@@ -658,6 +658,7 @@ describe('MdSlider without forms', () => {
658658

659659
testComponent = fixture.debugElement.componentInstance;
660660
spyOn(testComponent, 'onChange');
661+
spyOn(testComponent, 'onInput');
661662

662663
sliderDebugElement = fixture.debugElement.query(By.directive(MdSlider));
663664
sliderNativeElement = sliderDebugElement.nativeElement;
@@ -691,6 +692,30 @@ describe('MdSlider without forms', () => {
691692

692693
expect(testComponent.onChange).toHaveBeenCalledTimes(1);
693694
});
695+
696+
it('should dispatch events when changing back to previously emitted value after ' +
697+
'programmatically setting value', () => {
698+
expect(testComponent.onChange).not.toHaveBeenCalled();
699+
expect(testComponent.onInput).not.toHaveBeenCalled();
700+
701+
dispatchClickEventSequence(sliderNativeElement, 0.2);
702+
fixture.detectChanges();
703+
704+
expect(testComponent.onChange).toHaveBeenCalledTimes(1);
705+
expect(testComponent.onInput).toHaveBeenCalledTimes(1);
706+
707+
testComponent.slider.value = 0;
708+
fixture.detectChanges();
709+
710+
expect(testComponent.onChange).toHaveBeenCalledTimes(1);
711+
expect(testComponent.onInput).toHaveBeenCalledTimes(1);
712+
713+
dispatchClickEventSequence(sliderNativeElement, 0.2);
714+
fixture.detectChanges();
715+
716+
expect(testComponent.onChange).toHaveBeenCalledTimes(2);
717+
expect(testComponent.onInput).toHaveBeenCalledTimes(2);
718+
});
694719
});
695720

696721
describe('slider with input event', () => {
@@ -1351,6 +1376,8 @@ class SliderWithValueGreaterThanMax { }
13511376
class SliderWithChangeHandler {
13521377
onChange() { }
13531378
onInput() { }
1379+
1380+
@ViewChild(MdSlider) slider: MdSlider;
13541381
}
13551382

13561383
@Component({

src/lib/slider/slider.ts

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -385,15 +385,12 @@ export class MdSlider extends _MdSliderMixinBase
385385

386386
private _controlValueAccessorChangeFn: (value: any) => void = () => {};
387387

388-
/** The last value for which a change event was emitted. */
389-
private _lastChangeValue: number | null;
390-
391-
/** The last value for which an input event was emitted. */
392-
private _lastInputValue: number | null;
393-
394388
/** Decimal places to round to, based on the step amount. */
395389
private _roundLabelTo: number;
396390

391+
/** The value of the slider when the slide start event fires. */
392+
private _valueOnSlideStart: number | null;
393+
397394
/**
398395
* Whether mouse events should be converted to a slider position by calculating their distance
399396
* from the right or bottom edge of the slider as opposed to the top or left.
@@ -438,13 +435,16 @@ export class MdSlider extends _MdSliderMixinBase
438435
return;
439436
}
440437

438+
let oldValue = this.value;
441439
this._isSliding = false;
442440
this._renderer.addFocus();
443441
this._updateValueFromPosition({x: event.clientX, y: event.clientY});
444442

445-
/* Emits a change and input event if the value changed. */
446-
this._emitInputEvent();
447-
this._emitValueIfChanged();
443+
/* Emit a change and input event if the value changed. */
444+
if (oldValue != this.value) {
445+
this._emitInputEvent();
446+
this._emitChangeEvent();
447+
}
448448
}
449449

450450
_onSlide(event: HammerInput) {
@@ -460,10 +460,14 @@ export class MdSlider extends _MdSliderMixinBase
460460

461461
// Prevent the slide from selecting anything else.
462462
event.preventDefault();
463+
464+
let oldValue = this.value;
463465
this._updateValueFromPosition({x: event.center.x, y: event.center.y});
464466

465467
// Native range elements always emit `input` events when the value changed while sliding.
466-
this._emitInputEvent();
468+
if (oldValue != this.value) {
469+
this._emitInputEvent();
470+
}
467471
}
468472

469473
_onSlideStart(event: HammerInput | null) {
@@ -476,6 +480,7 @@ export class MdSlider extends _MdSliderMixinBase
476480

477481
this._isSliding = true;
478482
this._renderer.addFocus();
483+
this._valueOnSlideStart = this.value;
479484

480485
if (event) {
481486
this._updateValueFromPosition({x: event.center.x, y: event.center.y});
@@ -485,7 +490,11 @@ export class MdSlider extends _MdSliderMixinBase
485490

486491
_onSlideEnd() {
487492
this._isSliding = false;
488-
this._emitValueIfChanged();
493+
494+
if (this._valueOnSlideStart != this.value) {
495+
this._emitChangeEvent();
496+
}
497+
this._valueOnSlideStart = null;
489498
}
490499

491500
_onFocus() {
@@ -502,6 +511,8 @@ export class MdSlider extends _MdSliderMixinBase
502511
_onKeydown(event: KeyboardEvent) {
503512
if (this.disabled) { return; }
504513

514+
let oldValue = this.value;
515+
505516
switch (event.keyCode) {
506517
case PAGE_UP:
507518
this._increment(10);
@@ -540,8 +551,11 @@ export class MdSlider extends _MdSliderMixinBase
540551
// it.
541552
return;
542553
}
543-
this._emitInputEvent();
544-
this._emitValueIfChanged();
554+
555+
if (oldValue != this.value) {
556+
this._emitInputEvent();
557+
this._emitChangeEvent();
558+
}
545559

546560
this._isSliding = true;
547561
event.preventDefault();
@@ -581,22 +595,14 @@ export class MdSlider extends _MdSliderMixinBase
581595
}
582596

583597
/** Emits a change event if the current value is different from the last emitted value. */
584-
private _emitValueIfChanged() {
585-
if (this.value != this._lastChangeValue) {
586-
let event = this._createChangeEvent();
587-
this._lastChangeValue = this.value;
588-
this._controlValueAccessorChangeFn(this.value);
589-
this.change.emit(event);
590-
}
598+
private _emitChangeEvent() {
599+
this._controlValueAccessorChangeFn(this.value);
600+
this.change.emit(this._createChangeEvent());
591601
}
592602

593603
/** Emits an input event when the current value is different from the last emitted value. */
594604
private _emitInputEvent() {
595-
if (this.value != this._lastInputValue) {
596-
let event = this._createChangeEvent();
597-
this._lastInputValue = this.value;
598-
this.input.emit(event);
599-
}
605+
this.input.emit(this._createChangeEvent());
600606
}
601607

602608
/** Updates the amount of space between ticks as a percentage of the width of the slider. */

0 commit comments

Comments
 (0)