Skip to content

Commit 43bfbac

Browse files
committed
fix(material-experimental/mdc-slider): thumb incorrectly positioned when inside an overlay (#25288)
Fixes an issue where the thumb of an MDC slider wasn't positioned correctly when it has an initial value inside an overlay that is being animated. There are multiple ways to resolve this, but I ended up doing it by removing our logic that skips the first `ResizeObserver` emission since we can get around the performance issues with the `layout` call by reusing the dimensions provided in the callback. Fixes #25286. (cherry picked from commit fb4d7a0)
1 parent 17aaa64 commit 43bfbac

File tree

1 file changed

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

1 file changed

+20
-12
lines changed

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

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,9 @@ export class MatSlider
702702
/** Timeout used to debounce resize listeners. */
703703
private _resizeTimer: number;
704704

705+
/** Cached dimensions of the host element. */
706+
private _cachedHostRect: DOMRect | null;
707+
705708
constructor(
706709
readonly _ngZone: NgZone,
707710
readonly _cdr: ChangeDetectorRef,
@@ -941,6 +944,11 @@ export class MatSlider
941944
return this.disabled || this.disableRipple || !!this._globalRippleOptions?.disabled;
942945
}
943946

947+
/** Gets the dimensions of the host element. */
948+
_getHostDimensions() {
949+
return this._cachedHostRect || this._elementRef.nativeElement.getBoundingClientRect();
950+
}
951+
944952
/** Starts observing and updating the slider if the host changes its size. */
945953
private _observeHostResize() {
946954
if (typeof ResizeObserver === 'undefined' || !ResizeObserver) {
@@ -949,18 +957,18 @@ export class MatSlider
949957

950958
// MDC only updates the slider when the window is resized which
951959
// doesn't capture changes of the container itself. We use a resize
952-
// observer to ensure that the layout is correct (see #24590).
960+
// observer to ensure that the layout is correct (see #24590 and #25286).
953961
this._ngZone.runOutsideAngular(() => {
954-
// The callback will fire as soon as an element is observed and
955-
// we only want to know after the initial layout.
956-
let hasResized = false;
957-
this._resizeObserver = new ResizeObserver(() => {
958-
if (hasResized) {
959-
// Debounce the layouts since they can happen frequently.
960-
clearTimeout(this._resizeTimer);
961-
this._resizeTimer = setTimeout(this._layout, 50);
962-
}
963-
hasResized = true;
962+
this._resizeObserver = new ResizeObserver(entries => {
963+
clearTimeout(this._resizeTimer);
964+
this._resizeTimer = setTimeout(() => {
965+
// The `layout` call is going to call `getBoundingClientRect` to update the dimensions
966+
// of the host. Since the `ResizeObserver` already calculated them, we can save some
967+
// work by returning them instead of having to check the DOM again.
968+
this._cachedHostRect = entries[0]?.contentRect;
969+
this._layout();
970+
this._cachedHostRect = null;
971+
}, 50);
964972
});
965973
this._resizeObserver.observe(this._elementRef.nativeElement);
966974
});
@@ -1130,7 +1138,7 @@ class SliderAdapter implements MDCSliderAdapter {
11301138
return this._delegate._getThumbElement(thumbPosition).getBoundingClientRect();
11311139
};
11321140
getBoundingClientRect = (): DOMRect => {
1133-
return this._delegate._elementRef.nativeElement.getBoundingClientRect();
1141+
return this._delegate._getHostDimensions();
11341142
};
11351143
getValueIndicatorContainerWidth = (thumbPosition: Thumb): number => {
11361144
return this._delegate._getValueIndicatorContainerElement(thumbPosition).getBoundingClientRect()

0 commit comments

Comments
 (0)