diff --git a/src/material-experimental/mdc-slider/slider.ts b/src/material-experimental/mdc-slider/slider.ts index 789883465a48..4f968bf9a337 100644 --- a/src/material-experimental/mdc-slider/slider.ts +++ b/src/material-experimental/mdc-slider/slider.ts @@ -702,6 +702,9 @@ export class MatSlider /** Timeout used to debounce resize listeners. */ private _resizeTimer: number; + /** Cached dimensions of the host element. */ + private _cachedHostRect: DOMRect | null; + constructor( readonly _ngZone: NgZone, readonly _cdr: ChangeDetectorRef, @@ -941,6 +944,11 @@ export class MatSlider return this.disabled || this.disableRipple || !!this._globalRippleOptions?.disabled; } + /** Gets the dimensions of the host element. */ + _getHostDimensions() { + return this._cachedHostRect || this._elementRef.nativeElement.getBoundingClientRect(); + } + /** Starts observing and updating the slider if the host changes its size. */ private _observeHostResize() { if (typeof ResizeObserver === 'undefined' || !ResizeObserver) { @@ -949,18 +957,18 @@ export class MatSlider // MDC only updates the slider when the window is resized which // doesn't capture changes of the container itself. We use a resize - // observer to ensure that the layout is correct (see #24590). + // observer to ensure that the layout is correct (see #24590 and #25286). this._ngZone.runOutsideAngular(() => { - // The callback will fire as soon as an element is observed and - // we only want to know after the initial layout. - let hasResized = false; - this._resizeObserver = new ResizeObserver(() => { - if (hasResized) { - // Debounce the layouts since they can happen frequently. - clearTimeout(this._resizeTimer); - this._resizeTimer = setTimeout(this._layout, 50); - } - hasResized = true; + this._resizeObserver = new ResizeObserver(entries => { + clearTimeout(this._resizeTimer); + this._resizeTimer = setTimeout(() => { + // The `layout` call is going to call `getBoundingClientRect` to update the dimensions + // of the host. Since the `ResizeObserver` already calculated them, we can save some + // work by returning them instead of having to check the DOM again. + this._cachedHostRect = entries[0]?.contentRect; + this._layout(); + this._cachedHostRect = null; + }, 50); }); this._resizeObserver.observe(this._elementRef.nativeElement); }); @@ -1130,7 +1138,7 @@ class SliderAdapter implements MDCSliderAdapter { return this._delegate._getThumbElement(thumbPosition).getBoundingClientRect(); }; getBoundingClientRect = (): DOMRect => { - return this._delegate._elementRef.nativeElement.getBoundingClientRect(); + return this._delegate._getHostDimensions(); }; getValueIndicatorContainerWidth = (thumbPosition: Thumb): number => { return this._delegate._getValueIndicatorContainerElement(thumbPosition).getBoundingClientRect()