Browse Source

fix(dynamic-dialog): fix overlay container scoping and lifecycle management

- Scope DynamicOverlayContainer and related providers to an isolated child injector created per DynamicMatDialog instance, preventing shared state leaks across multiple dialog usages
- Introduce PARENT_OVERLAY_CONTAINER token so DynamicOverlayContainer can fall back to the global overlay container when no custom element is set
- Replace _containerElement assignment with a local _customElement field and override getContainerElement() for clean delegation logic
- Simplify open() method using try/finally to ensure the container element is always reset after dialog creation, regardless of errors
pull/15069/head
Vladyslav_Prykhodko 5 months ago
committed by Vladyslav Prykhodko
parent
commit
2ed38acea7
  1. 39
      ui-ngx/src/app/shared/components/dialog/dynamic/dynamic-dialog.module.ts
  2. 19
      ui-ngx/src/app/shared/components/dialog/dynamic/dynamic-dialog.ts
  3. 16
      ui-ngx/src/app/shared/components/dialog/dynamic/dynamic-overlay-container.ts

39
ui-ngx/src/app/shared/components/dialog/dynamic/dynamic-dialog.module.ts

@ -15,36 +15,47 @@
///
import { Overlay, OverlayContainer, OverlayModule } from '@angular/cdk/overlay';
import { NgModule } from '@angular/core';
import { inject, Injector, NgModule } from '@angular/core';
import { DEFAULT_DIALOG_CONFIG, Dialog, DialogConfig, DialogModule } from '@angular/cdk/dialog';
import { MatDialogModule } from '@angular/material/dialog';
import { DynamicDialog, DynamicMatDialog } from './dynamic-dialog';
import { DynamicOverlay } from './dynamic-overlay';
import { DynamicOverlayContainer } from './dynamic-overlay-container';
import { DynamicOverlayContainer, PARENT_OVERLAY_CONTAINER } from './dynamic-overlay-container';
export const DYNAMIC_MAT_DIALOG_PROVIDERS = [
DynamicOverlayContainer,
{ provide: OverlayContainer, useExisting: DynamicOverlayContainer },
DynamicOverlay,
{ provide: Overlay, useExisting: DynamicOverlay },
DynamicDialog,
{ provide: Dialog, useExisting: DynamicDialog },
DynamicMatDialog,
{
provide: DEFAULT_DIALOG_CONFIG,
useValue: {
...new DialogConfig()
provide: DynamicMatDialog,
useFactory: () => {
const parentInjector = inject(Injector);
const parentOverlayContainer = parentInjector.get(OverlayContainer);
const customInjector = Injector.create({
providers: [
{ provide: PARENT_OVERLAY_CONTAINER, useValue: parentOverlayContainer },
DynamicOverlayContainer,
{ provide: OverlayContainer, useExisting: DynamicOverlayContainer },
DynamicOverlay,
{ provide: Overlay, useExisting: DynamicOverlay },
DynamicDialog,
{ provide: Dialog, useExisting: DynamicDialog },
DynamicMatDialog,
{ provide: DEFAULT_DIALOG_CONFIG, useValue: new DialogConfig() }
],
parent: parentInjector
});
return customInjector.get(DynamicMatDialog);
}
}
];
@NgModule( {
@NgModule({
imports: [
OverlayModule,
DialogModule,
MatDialogModule
],
providers: DYNAMIC_MAT_DIALOG_PROVIDERS
} )
})
export class DynamicMatDialogModule {
}

19
ui-ngx/src/app/shared/components/dialog/dynamic/dynamic-dialog.ts

@ -34,20 +34,13 @@ export class DynamicMatDialog extends MatDialog {
config.containerElement.style.transform = 'translateZ(0)';
this._customOverlay.setContainerElement(config.containerElement);
}
const ref = super.open(component, config);
if (config?.containerElement) {
ref.afterClosed().subscribe(
{
next: () => {
this._customOverlay.setContainerElement(null);
},
error: () => {
this._customOverlay.setContainerElement(null);
}
}
);
try {
return super.open(component, config);
} finally {
if (config?.containerElement) {
this._customOverlay.setContainerElement(null);
}
}
return ref;
}
}

16
ui-ngx/src/app/shared/components/dialog/dynamic/dynamic-overlay-container.ts

@ -15,13 +15,21 @@
///
import { OverlayContainer } from "@angular/cdk/overlay";
import { Injectable } from "@angular/core";
import { inject, Injectable, InjectionToken } from "@angular/core";
export const PARENT_OVERLAY_CONTAINER = new InjectionToken<OverlayContainer>('PARENT_OVERLAY_CONTAINER');
@Injectable()
export class DynamicOverlayContainer extends OverlayContainer {
public setContainerElement( containerElement:HTMLElement ):void {
private _globalContainer = inject(PARENT_OVERLAY_CONTAINER);
private _customElement: HTMLElement | null = null;
public override getContainerElement(): HTMLElement {
return this._customElement || this._globalContainer.getContainerElement();
}
this._containerElement = containerElement;
setContainerElement(element: HTMLElement | null): void {
this._customElement = element;
}
}
}
Loading…
Cancel
Save