Skip to content

Commit 174c99e

Browse files
crisbetoamysorto
authored andcommitted
fix(material-experimental/mdc-slider): event handling fixes and cleanup (#23063)
* Fixes that the `mouseenter` and `mouseleave` handlers on the slider were leaking. It was `Function.bind` returns a new function and we weren't passing the same function in when the component is destroyed. * Fixes that slider was calling `unsubscribe` on subjects that belong to the slider thumbs. `Subject.unsubscribe` will drop all subscriptions to the observable, including ones that come from the outside. The correct thing to do is to either complete the observables or save a reference to the `Subscription` and call `unsubscribe` on it. * Removes the `*Ctor` interfaces from the mixin class since it isn't necessary anymore. (cherry picked from commit 91fa44e)
1 parent 155cfea commit 174c99e

File tree

1 file changed

+20
-23
lines changed
  • src/material-experimental/mdc-slider

1 file changed

+20
-23
lines changed

src/material-experimental/mdc-slider/slider.ts

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ import {
3939
} from '@angular/core';
4040
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
4141
import {
42-
CanColorCtor,
4342
CanDisableRipple,
44-
CanDisableRippleCtor,
4543
MatRipple,
4644
MAT_RIPPLE_GLOBAL_OPTIONS,
4745
mixinColor,
@@ -132,30 +130,27 @@ export class MatSliderVisualThumb implements AfterViewInit, OnDestroy {
132130
this._ripple.radius = 24;
133131
this._sliderInput = this._slider._getInput(this.thumbPosition);
134132

135-
this._sliderInput.dragStart.subscribe((e: MatSliderDragEvent) => this._onDragStart(e));
136-
this._sliderInput.dragEnd.subscribe((e: MatSliderDragEvent) => this._onDragEnd(e));
133+
// Note that we don't unsubscribe from these, because they're complete on destroy.
134+
this._sliderInput.dragStart.subscribe(event => this._onDragStart(event));
135+
this._sliderInput.dragEnd.subscribe(event => this._onDragEnd(event));
137136

138137
this._sliderInput._focus.subscribe(() => this._onFocus());
139138
this._sliderInput._blur.subscribe(() => this._onBlur());
140139

141140
// These two listeners don't update any data bindings so we bind them
142-
// outside of the NgZone to pervent angular from needlessly running change detection.
141+
// outside of the NgZone to prevent Angular from needlessly running change detection.
143142
this._ngZone.runOutsideAngular(() => {
144-
this._elementRef.nativeElement.addEventListener('mouseenter', this._onMouseEnter.bind(this));
145-
this._elementRef.nativeElement.addEventListener('mouseleave', this._onMouseLeave.bind(this));
143+
this._elementRef.nativeElement.addEventListener('mouseenter', this._onMouseEnter);
144+
this._elementRef.nativeElement.addEventListener('mouseleave', this._onMouseLeave);
146145
});
147146
}
148147

149148
ngOnDestroy() {
150-
this._sliderInput.dragStart.unsubscribe();
151-
this._sliderInput.dragEnd.unsubscribe();
152-
this._sliderInput._focus.unsubscribe();
153-
this._sliderInput._blur.unsubscribe();
154149
this._elementRef.nativeElement.removeEventListener('mouseenter', this._onMouseEnter);
155150
this._elementRef.nativeElement.removeEventListener('mouseleave', this._onMouseLeave);
156151
}
157152

158-
private _onMouseEnter(): void {
153+
private _onMouseEnter = (): void => {
159154
this._isHovered = true;
160155
// We don't want to show the hover ripple on top of the focus ripple.
161156
// This can happen if the user tabs to a thumb and then the user moves their cursor over it.
@@ -164,7 +159,7 @@ export class MatSliderVisualThumb implements AfterViewInit, OnDestroy {
164159
}
165160
}
166161

167-
private _onMouseLeave(): void {
162+
private _onMouseLeave = (): void => {
168163
this._isHovered = false;
169164
this._hoverRippleRef?.fadeOut();
170165
}
@@ -279,7 +274,7 @@ export class MatSliderVisualThumb implements AfterViewInit, OnDestroy {
279274
multi: true
280275
}],
281276
})
282-
export class MatSliderThumb implements AfterViewInit, ControlValueAccessor, OnInit {
277+
export class MatSliderThumb implements AfterViewInit, ControlValueAccessor, OnInit, OnDestroy {
283278

284279
// ** IMPORTANT NOTE **
285280
//
@@ -315,7 +310,7 @@ export class MatSliderThumb implements AfterViewInit, ControlValueAccessor, OnIn
315310
* to facilitate the two-way binding for the `value` input.
316311
* @docs-private
317312
*/
318-
@Output() readonly valueChange: EventEmitter<number> = new EventEmitter<number>();
313+
@Output() readonly valueChange: EventEmitter<number> = new EventEmitter<number>();
319314

320315
/** Event emitted when the slider thumb starts being dragged. */
321316
@Output() readonly dragStart: EventEmitter<MatSliderDragEvent>
@@ -386,6 +381,14 @@ export class MatSliderThumb implements AfterViewInit, ControlValueAccessor, OnIn
386381
}
387382
}
388383

384+
ngOnDestroy() {
385+
this.dragStart.complete();
386+
this.dragEnd.complete();
387+
this._focus.complete();
388+
this._blur.complete();
389+
this.valueChange.complete();
390+
}
391+
389392
_onBlur(): void {
390393
this._onTouched();
391394
this._blur.emit();
@@ -512,15 +515,9 @@ export class MatSliderThumb implements AfterViewInit, ControlValueAccessor, OnIn
512515
}
513516

514517
// Boilerplate for applying mixins to MatSlider.
515-
/** @docs-private */
516-
class MatSliderBase {
518+
const _MatSliderMixinBase = mixinColor(mixinDisableRipple(class {
517519
constructor(public _elementRef: ElementRef<HTMLElement>) {}
518-
}
519-
const _MatSliderMixinBase:
520-
CanColorCtor &
521-
CanDisableRippleCtor &
522-
typeof MatSliderBase =
523-
mixinColor(mixinDisableRipple(MatSliderBase), 'primary');
520+
}), 'primary');
524521

525522
/**
526523
* Allows users to select from a range of values by moving the slider thumb. It is similar in

0 commit comments

Comments
 (0)