MatSlider change event is fired twice when slider knob is dragged and released. Surprisingly enough, this happens only sometimes.
Event emitted when the slider value has changed.
MatSlider change event is fired twice when slider knob is dragged and released.
See: stackblitz
It fires immediately if you don't click exactly in the center of the knob.
It probably because we change the value on mousedown
and then while the user is dragging. This sounds like it's working as expected.
This is happening to me on every single iOS devices, any suggestions?
It probably because we change the value on
mousedown
and then while the user is dragging. This sounds like it's working as expected.
I'm sure an end-user doesn't expect the value to be changed, just because he/she grabbed the knob 1 pixel on the left of the knob center :)
I think the behavior should be on the mouseup event, to avoid this situation.
The problem, if we were to do that, is that the events will no longer be in sync with what is being rendered on screen.
Confirmed, it's an unexpected behavior (bug).
https://stackblitz.com/edit/angular-mat-slider-full-options?embed=1&file=app/slider-configurable-example.html
If you click on the thumb if the slider is not focused an begin to drag the change event is emitted.
Also if you slick on the range (line, not the thumb) the change event is always fired on mouse button down. And final on pointer (mouse / touch) up (as expected).
Whatever the component does for internal reasons, the output interface "(change)" should only be fired once on pointer up. You can keep change detection on pointer down internal for the component. But not for the output change.
@crisbeto It's only about the output event of the component. You can do anything internal. Inside the component you can use mouse down whatever to render the current value. BUT the interface output (change) event should only be fired once. You could split the output event value with a internal value and only emit the value for output on mouse up / pointer up / etc.
Here's the current behavior.
You see that the change event is fired when the user just press the mouse button down to begin dragging. This is an unexpected behavior. (bug) It's expected on mouse button up.
The yellow circle indicates the pressed mouse button.
Workaround:
Use the event slideend
.
<mat-slider
#mySlider
(slideend)="sliderOnChange(mySlider.value)"
></mat-slider>
````
This is the "real" (expected) "change"-event.
I use the same event like the slider does.
https://github.com/angular/material2/blob/7.3.5/src/lib/slider/slider.ts#L121
UPDATE:
Known issue: With (slideend) a simple click on the range-line of the slider does not fire the slideend until it has never been dragged. https://github.com/angular/material2/issues/2767
Alternative you can listen on the (mouseup) event or (pointerup). With these events you have to implement a change-detection.
You'll also have problem if your cursor is not overlapping the component on pointerup. Therefore you have to handle cancle events. And and and... Just fix this issue please 馃槃
UPDATE:
I found a solution for the slideend / pointerup issue. Just combine it with a simple change-detection.
```html
<mat-slider
#mySlider
(slideend)="sliderOnChange(mySlider.value)"
(pointerup)="sliderOnChange(mySlider.value)"
></mat-slider>
````
```ts
sliderOnChange(value: number) {
if (this.mySliderValue !== value) {
this.mySliderValue = value;
console.log('changed: ', value);
}
}
Ok, now it works. THIS is the "real" "change"-event as expected. But just a workaround.
Well, the slideend
event is not available now :(
Bug:
MatSlider change event is fired twice when slider knob is dragged and released. Surprisingly enough, this happens only sometimes.
What is the expected behavior?
Event emitted when the slider value has changed.
What is the current behavior?
MatSlider change event is fired twice when slider knob is dragged and released.
What are the steps to reproduce?
See: stackblitz
What is the use-case or motivation for changing an existing behavior?
Which versions of Angular, Material, OS, TypeScript, browsers are affected?
Is there anything else we should know?
i have faced same problem please let me know what is right solution of this bug????
Well, the
slideend
event is not available now :(
I have a little work around that seems to work so far... Please don't fire at me if it doesn't for you ;)
<mat-slider min="0"
max="100"
step="1"
(input)="sliderSliding( $event )"
(change)="sliderChanged( $event )"
(mouseup)="sliderMouseButtonReleased( $event )"
[(ngModel)]="value">
</mat-slider>
public value: number = 0;
private _slidingValue: number;
public sliderSliding( args: MatSliderChange ): void {
this._slidingValue = args.value;
}
public sliderMouseButtonReleased( args: MouseEvent ): void {
if ( this.value === this._slidingValue ) {
this.sliderChanged( null );
}
}
public sliderChanged( args: any ): void {
if ( !!args && !!args.source._lastPointerEvent ) {
return;
}
// Your code to process the event here
}
For those who - like me - desperately need a workaround: I downloaded the material repository and moved all necessary files to my project. Then, in src/material/slider/slider.ts in method _pointerDown
(line 620) I removed line 644, which is this: this._emitChangeEvent();
.
This works for my case, but bear in mind, that I haven't run any automated tests againist this change. Hope this helps
Well, the
slideend
event is not available now :(I have a little work around that seems to work so far... Please don't fire at me if it doesn't for you ;)
<mat-slider min="0" max="100" step="1" (input)="sliderSliding( $event )" (change)="sliderChanged( $event )" (mouseup)="sliderMouseButtonReleased( $event )" [(ngModel)]="value"> </mat-slider>
public value: number = 0; private _slidingValue: number; public sliderSliding( args: MatSliderChange ): void { this._slidingValue = args.value; } public sliderMouseButtonReleased( args: MouseEvent ): void { if ( this.value === this._slidingValue ) { this.sliderChanged( null ); } } public sliderChanged( args: any ): void { if ( !!args && !!args.source._lastPointerEvent ) { return; } // Your code to process the event here }
Thanks! This helped me out a lot, but I noticed that you will still get multiple events fired when using a touch device or if using a keyboard to move the slider.
I found a simpler way of working around the issue is instead of binding to the change event, to bind to mouseup, keyup and touchend to cover keyboard, mouse and touch. If you do this you no longer need the sliderMouseButtonReleased function and can remove the return at the start of sliderChanged e.g.
<mat-slider min="0"
max="100"
step="1"
(input)="sliderSliding( $event )"
(mouseup)="sliderChanged( $event )"
(keyup)="sliderChanged( $event )"
(touchend)="sliderChanged( $event )"
[(ngModel)]="value">
</mat-slider>
public value: number = 0;
private _slidingValue: number;
public sliderSliding( args: MatSliderChange ): void {
this._slidingValue = args.value;
}
public sliderChanged( args: any ): void {
// Your code to process the event here
}
(mouseup)="sliderChanged( $event )" (keyup)="sliderChanged( $event )" (touchend)="sliderChanged( $event )"
touchend event is not emitted by mat-slider. Did you test that pls?
(mouseup)="sliderChanged( $event )" (keyup)="sliderChanged( $event )" (touchend)="sliderChanged( $event )"
touchend event is not emitted by mat-slider. Did you test that pls?
Appeared to work when I tested it - without touchend and after removing change was not getting any events fired from a touch device.
Well, the
slideend
event is not available now :(I have a little work around that seems to work so far... Please don't fire at me if it doesn't for you ;)
<mat-slider min="0" max="100" step="1" (input)="sliderSliding( $event )" (change)="sliderChanged( $event )" (mouseup)="sliderMouseButtonReleased( $event )" [(ngModel)]="value"> </mat-slider>
public value: number = 0; private _slidingValue: number; public sliderSliding( args: MatSliderChange ): void { this._slidingValue = args.value; } public sliderMouseButtonReleased( args: MouseEvent ): void { if ( this.value === this._slidingValue ) { this.sliderChanged( null ); } } public sliderChanged( args: any ): void { if ( !!args && !!args.source._lastPointerEvent ) { return; } // Your code to process the event here }
Thanks! This helped me out a lot, but I noticed that you will still get multiple events fired when using a touch device or if using a keyboard to move the slider.
I found a simpler way of working around the issue is instead of binding to the change event, to bind to mouseup, keyup and touchend to cover keyboard, mouse and touch. If you do this you no longer need the sliderMouseButtonReleased function and can remove the return at the start of sliderChanged e.g.<mat-slider min="0" max="100" step="1" (input)="sliderSliding( $event )" (mouseup)="sliderChanged( $event )" (keyup)="sliderChanged( $event )" (touchend)="sliderChanged( $event )" [(ngModel)]="value"> </mat-slider>
public value: number = 0; private _slidingValue: number; public sliderSliding( args: MatSliderChange ): void { this._slidingValue = args.value; } public sliderChanged( args: any ): void { // Your code to process the event here }
pls
(mouseup)="sliderChanged( $event )" (keyup)="sliderChanged( $event )" (touchend)="sliderChanged( $event )"
touchend event is not emitted by mat-slider. Did you test that pls?
Appeared to work when I tested it - without touchend and after removing change was not getting any events fired from a touch device.
touchend doesn't work for me. I used panend (from Hammer.js) event instead of it and it work properly now. Thank you for sharing workaround
Bumping to P2 since people seem to continue to run into this. I also submitted a fix at #20240, but I suspect that it might be difficult to get it merged in, because it can break people's tests.
Thanks for fixing! Workaround no longer required
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._
Most helpful comment
Workaround:
Use the event
slideend
.Ok, now it works. THIS is the "real" "change"-event as expected. But just a workaround.