From c8c7068602b5ddf5aac736c9147e573f3a3ff720 Mon Sep 17 00:00:00 2001 From: Dumitrescu Alexandru <89769969+adumitrescu-plenty@users.noreply.github.com> Date: Tue, 18 Jun 2024 10:31:20 +0300 Subject: [PATCH] perf(material/form-field): add caching for shadow root Add caching for shadow root so it doesn't have to be resolved each time --- src/material/form-field/form-field.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/material/form-field/form-field.ts b/src/material/form-field/form-field.ts index 2cbef3e18b6d..52c755ae6daf 100644 --- a/src/material/form-field/form-field.ts +++ b/src/material/form-field/form-field.ts @@ -316,6 +316,13 @@ export class MatFormField private _explicitFormFieldControl: MatFormFieldControl; private _needsOutlineLabelOffsetUpdate = false; + /** + * Cached shadow root that the element is placed in. `null` means that the element isn't in + * the shadow DOM and `undefined` means that it hasn't been resolved yet. Should be read via + * `_getShadowRoot`, not directly. + */ + private _cachedShadowRoot: ShadowRoot | null | undefined; + private _injector = inject(Injector); constructor( @@ -720,7 +727,21 @@ export class MatFormField rootNode !== element && // If the rootNode is the document we need to make sure that the element is visible ((rootNode === document && element.offsetParent !== null) || - rootNode === _getShadowRoot(element)) + rootNode === this._getShadowRoot()) ); } + + /** + * Lazily resolves and returns the shadow root of the element. We do this in a function, rather + * than saving it in property directly on init, because we want to resolve it as late as possible + * in order to ensure that the element has been moved into the shadow DOM. Doing it inside the + * constructor might be too early if the element is inside of something like `ngFor` or `ngIf`. + */ + private _getShadowRoot(): ShadowRoot | null { + if (this._cachedShadowRoot === undefined) { + this._cachedShadowRoot = _getShadowRoot(this._elementRef.nativeElement); + } + + return this._cachedShadowRoot; + } }