From 9497b02f8befb7cc5c81018b0136315758cc2853 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sun, 27 Mar 2022 03:53:49 +0200 Subject: [PATCH] fix(material-experimental/mdc-slider): update layout when container resizes (#24648) Currently the layout of the slider can look broken, because the thumb positions don't update when the size of the container changes. These changes add some extra logic to trigger the resize in such cases. Fixes #24590. (cherry picked from commit 87ab4f49dba39e16dc0e5dc005351d487cc169d3) --- .../mdc-slider/slider.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/material-experimental/mdc-slider/slider.ts b/src/material-experimental/mdc-slider/slider.ts index 8c3cf14dc949..f657c93b561c 100644 --- a/src/material-experimental/mdc-slider/slider.ts +++ b/src/material-experimental/mdc-slider/slider.ts @@ -693,6 +693,12 @@ export class MatSlider /** Subscription to changes to the directionality (LTR / RTL) context for the application. */ private _dirChangeSubscription: Subscription; + /** Observer used to monitor size changes in the slider. */ + private _resizeObserver: ResizeObserver | null; + + /** Timeout used to debounce resize listeners. */ + private _resizeTimer: number; + constructor( readonly _ngZone: NgZone, readonly _cdr: ChangeDetectorRef, @@ -727,6 +733,7 @@ export class MatSlider this._foundation.init(); this._foundation.layout(); this._initialized = true; + this._observeHostResize(); } // The MDC foundation requires access to the view and content children of the MatSlider. In // order to access the view and content children of MatSlider we need to wait until change @@ -746,6 +753,9 @@ export class MatSlider this._foundation.destroy(); } this._dirChangeSubscription.unsubscribe(); + this._resizeObserver?.disconnect(); + this._resizeObserver = null; + clearTimeout(this._resizeTimer); this._removeUISyncEventListener(); } @@ -919,6 +929,31 @@ export class MatSlider _isRippleDisabled(): boolean { return this.disabled || this.disableRipple || !!this._globalRippleOptions?.disabled; } + + /** Starts observing and updating the slider if the host changes its size. */ + private _observeHostResize() { + if (typeof ResizeObserver === 'undefined' || !ResizeObserver) { + return; + } + + // 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). + 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.observe(this._elementRef.nativeElement); + }); + } } /** The MDCSliderAdapter implementation. */