Reputation: 129
I'm using a mat-slider to let the user set a value.
The (input)
event emitter is used for displaying the value "live" (while mouse still down).
This is working.
At the moment the (change)
event emitter is used to recognize when the user has selected a value (released mouse).
The first problem is that the change event is fired twice during a normal interaction with the slider: once on the initial click on the slider and the second time when releasing it. I would like to have the event fired only upon releasing the slider, or to have a function which can differentiate between the two events and act only upon the release event.
The second problem is that I have to make an HTTP request when a new value from the slider is set. I don't want this to happen to often, so I would like to have a kind of a timeout. Only when a certain amount of time has passed and no new change event occured, do I want to make the HTTP request.
I already tried to implement this with a lock, but it didn't work because sometimes only one change event is fired (for example when clicking on the slider and not dragging it), and then the lock variable is flipped wrongly and the lock mechanism is not working anymore because of the inverted variable.
Is there any way to resolve these problems and to achieve what I want?
Upvotes: 3
Views: 11714
Reputation: 1908
You can use debounceTime to ensure there is a certain time delay between events before a HTTP request is triggered.
Example:
@Component({template: `<mat-slider (input)="onSlide($event)"></mat-slider>`})
export class DelayedSliderComponent implements OnInit {
valueSubject = new BehaviorSubject<number>(0);
ngOnInit() {
this.valueSubject.pipe(debounceTime(1000)).subscribe(value => {
// http request can go here
});
}
onSlide(event: MatSliderChange) {
this.valueSubject.next(event.value);
}
}
The above component contains a slider that binds to the input event. This input event triggers every single time the value changes, without delay. The valueSubject gets the new value every single time onSlide is called, but because of debounceTime(1000) the subscribers will only receive any new value when there's been at least one full second (or 1000 milliseconds) since the last time the value changed.
Upvotes: 9
Reputation: 5656
It's a bug. See https://github.com/angular/material2/issues/14363
Workaround:
Use the event slideend
.
<mat-slider
#mySlider
(slideend)="sliderOnChange(mySlider.value)"
></mat-slider>
This is the "real" (expected) "change"-event.
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. Alternative you can listen on the (mouseup) event or (pointerup). But with pointerup etc. your mouse cursor has to be inside the component. (overlapping) otherwise you have to handle the abort-events of the pointer. ...
I found a solution for the slideend / pointerup issue. Just combine it with a simple change-detection.
<mat-slider
#mySlider
(slideend)="sliderOnChange(mySlider.value)"
(pointerup)="sliderOnChange(mySlider.value)"
></mat-slider>
sliderOnChange(value: number) {
if (this.mySliderValue!== value) {
this.mySliderValue= value;
console.log('changed: ', value);
}
}
You could add the keyup-event too to handle the keyboard input.
Upvotes: 5