+
diff --git a/src/demo-app/app/snippets/prevent-change-on-scroll-slider/prevent-change-on-scroll-slider.component.title-template.html b/src/demo-app/app/snippets/prevent-change-on-scroll-slider/prevent-change-on-scroll-slider.component.title-template.html
new file mode 100644
index 0000000..93fb412
--- /dev/null
+++ b/src/demo-app/app/snippets/prevent-change-on-scroll-slider/prevent-change-on-scroll-slider.component.title-template.html
@@ -0,0 +1 @@
+Prevent change on page scroll using touch gesture
diff --git a/src/demo-app/app/snippets/prevent-change-on-scroll-slider/prevent-change-on-scroll-slider.component.ts b/src/demo-app/app/snippets/prevent-change-on-scroll-slider/prevent-change-on-scroll-slider.component.ts
new file mode 100644
index 0000000..8d4b4cf
--- /dev/null
+++ b/src/demo-app/app/snippets/prevent-change-on-scroll-slider/prevent-change-on-scroll-slider.component.ts
@@ -0,0 +1,20 @@
+import { Component, HostListener, EventEmitter } from '@angular/core';
+import { Options } from '@local/ngx-slider';
+
+@Component({
+ selector: 'app-prevent-change-on-scroll-slider',
+ templateUrl: './prevent-change-on-scroll-slider.component.html'
+})
+export class PreventChangeOnScrollSliderComponent {
+ value: number = 100;
+ options: Options = {
+ floor: 0,
+ ceil: 250
+ };
+ emitOnScroll: EventEmitter = new EventEmitter;
+
+ @HostListener('window:scroll', ['$event'])
+ public onScroll(event: any): void {
+ this.emitOnScroll.emit();
+ }
+}
diff --git a/src/ngx-slider/lib/slider.component.ts b/src/ngx-slider/lib/slider.component.ts
index 4bb2ab8..5f0d47e 100644
--- a/src/ngx-slider/lib/slider.component.ts
+++ b/src/ngx-slider/lib/slider.component.ts
@@ -195,6 +195,18 @@ export class SliderComponent
);
}
+ private cancelUserChangeSubscription: any;
+ @Input() set cancelUserChange(cancelUserChange: EventEmitter) {
+ this.unsubscribeCancelUserChange();
+
+ this.cancelUserChangeSubscription = cancelUserChange.subscribe(() => {
+ if (this.moving) {
+ this.positionTrackingHandle(this.preStartHandleValue);
+ this.forceEnd(true);
+ }
+ });
+ }
+
// Slider type, true means range slider
public get range(): boolean {
return (
@@ -240,6 +252,8 @@ export class SliderComponent
private touchId: number = null;
// Values recorded when first dragging the bar
private dragging: Dragging = new Dragging();
+ // Value of hanlde at the beginning of onStart()
+ private preStartHandleValue: number = null;
/* Slider DOM elements */
@@ -575,6 +589,13 @@ export class SliderComponent
}
}
+ private unsubscribeCancelUserChange(): void {
+ if (!ValueHelper.isNullOrUndefined(this.cancelUserChangeSubscription)) {
+ this.cancelUserChangeSubscription.unsubscribe();
+ this.cancelUserChangeSubscription = null;
+ }
+ }
+
private getPointerElement(pointerType: PointerType): SliderHandleDirective {
if (pointerType === PointerType.Min) {
return this.minHandleElement;
@@ -2165,6 +2186,10 @@ export class SliderComponent
this.getPointerElement(pointerType);
pointerElement.active = true;
+ // Store currentTrackingValue as soon as it is available to allow
+ // the slide to be canceled. (E.g. on scroll detected.)
+ this.preStartHandleValue = this.getCurrentTrackingValue();
+
if (this.viewOptions.keyboardSupport) {
pointerElement.focus();
}
@@ -2294,18 +2319,16 @@ export class SliderComponent
this.positionTrackingHandle(newValue);
}
- private onEnd(event: MouseEvent | TouchEvent): void {
- if (CompatibilityHelper.isTouchEvent(event)) {
- const changedTouches: TouchList = (event as TouchEvent).changedTouches;
- if (changedTouches[0].identifier !== this.touchId) {
- return;
- }
- }
-
+ private forceEnd(disableAnimation: boolean = false): void {
this.moving = false;
if (this.viewOptions.animate) {
this.sliderElementAnimateClass = true;
}
+ if (disableAnimation) {
+ this.sliderElementAnimateClass = false;
+ // make sure the slider animate class is set according to the viewOptions after forceEnd() with disabled animations finishes
+ setTimeout(() => {this.sliderElementAnimateClass = this.viewOptions.animate});
+ }
this.touchId = null;
@@ -2322,6 +2345,17 @@ export class SliderComponent
this.userChangeEnd.emit(this.getChangeContext());
}
+ private onEnd(event: MouseEvent | TouchEvent): void {
+ if (CompatibilityHelper.isTouchEvent(event)) {
+ const changedTouches: TouchList = (event as TouchEvent).changedTouches;
+ if (changedTouches[0].identifier !== this.touchId) {
+ return;
+ }
+ }
+
+ this.forceEnd();
+ }
+
private onPointerFocus(pointerType: PointerType): void {
const pointerElement: SliderHandleDirective =
this.getPointerElement(pointerType);
diff --git a/typedoc/README.md b/typedoc/README.md
index 46d33ef..aaa8623 100644
--- a/typedoc/README.md
+++ b/typedoc/README.md
@@ -19,6 +19,7 @@ The slider component takes the following inputs and outputs:
[options]=""
[manualRefresh]=""
[triggerFocus]=""
+ [cancelUserChange]=""
(userChangeStart)=""
(userChange)=""
(userChangeEnd)=""
@@ -57,6 +58,10 @@ For a complete example, see the [dynamic options slider demo](routerLink:///demo
`triggerFocus` input is provided to set the focus programmatically on a slider handle. The emitter takes a `PointerType` as argument, or if left `undefined`, will default to `PointerType.Min`. Refer to the [example demo](routerLink:///demos#trigger-focus-slider) to see how it works.
+### Cancel user change
+
+`cancelUserChange` input ends current user intraction and restores value of a slider handle that was present before `userChangeStart` triggered. Refer to the [example demo](routerLink:///demos#prevent-change-on-scroll-slider) to see how it works.
+
### User change events
`userChangeStart`, `userChange` and `userChangeEnd` provide output events that are triggered by user interaction (through keyboard, mouse or touchpad). The event handler also passes a `ChangeContext` object which contains details about the changes. Refer to the [example demo](routerLink:///demos#user-events-slider) to see how it works.