From 30d246eb2b884dbc84ae96a5c6a16d2fa7cdb1d9 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sun, 11 Mar 2018 12:25:56 -0400 Subject: [PATCH] fix(slider): unable to slide to max value under certain conditions Fixes users not being to slide to the maximum value in a slider, in some cases, when the number of steps don't divide evenly into the maximum value. Fixes #10148. --- src/lib/slider/slider.spec.ts | 12 ++++++++++++ src/lib/slider/slider.ts | 25 +++++++++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/lib/slider/slider.spec.ts b/src/lib/slider/slider.spec.ts index ce00bfe0ddc0..422a590b0743 100644 --- a/src/lib/slider/slider.spec.ts +++ b/src/lib/slider/slider.spec.ts @@ -207,6 +207,18 @@ describe('MatSlider without forms', () => { it('should have aria-orientation horizontal', () => { expect(sliderNativeElement.getAttribute('aria-orientation')).toEqual('horizontal'); }); + + it('should slide to the max value when the steps do not divide evenly into it', () => { + sliderInstance.min = 5; + sliderInstance.max = 100; + sliderInstance.step = 15; + + dispatchSlideEventSequence(sliderNativeElement, 0, 1, gestureConfig); + fixture.detectChanges(); + + expect(sliderInstance.value).toBe(100); + }); + }); describe('disabled slider', () => { diff --git a/src/lib/slider/slider.ts b/src/lib/slider/slider.ts index 2e4bf60c5339..1ff871f598bd 100644 --- a/src/lib/slider/slider.ts +++ b/src/lib/slider/slider.ts @@ -635,16 +635,29 @@ export class MatSlider extends _MatSliderMixinBase // The exact value is calculated from the event and used to find the closest snap value. let percent = this._clamp((posComponent - offset) / size); + if (this._invertMouseCoords) { percent = 1 - percent; } - let exactValue = this._calculateValue(percent); - // This calculation finds the closest step by finding the closest whole number divisible by the - // step relative to the min. - let closestValue = Math.round((exactValue - this.min) / this.step) * this.step + this.min; - // The value needs to snap to the min and max. - this.value = this._clamp(closestValue, this.min, this.max); + // Since the steps may not divide cleanly into the max value, if the user + // slid to 0 or 100 percent, we jump to the min/max value. This approach + // is slightly more intuitive than using `Math.ceil` below, because it + // follows the user's pointer closer. + if (percent === 0) { + this.value = this.min; + } else if (percent === 1) { + this.value = this.max; + } else { + let exactValue = this._calculateValue(percent); + + // This calculation finds the closest step by finding the closest + // whole number divisible by the step relative to the min. + let closestValue = Math.round((exactValue - this.min) / this.step) * this.step + this.min; + + // The value needs to snap to the min and max. + this.value = this._clamp(closestValue, this.min, this.max); + } } /** Emits a change event if the current value is different from the last emitted value. */