mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(overlay): remove overlay container on destroy (#5378)
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable, Optional, SkipSelf} from '@angular/core';
|
||||
import {Injectable, Optional, SkipSelf, OnDestroy} from '@angular/core';
|
||||
|
||||
|
||||
/**
|
||||
@@ -14,7 +14,7 @@ import {Injectable, Optional, SkipSelf} from '@angular/core';
|
||||
* It should be provided in the root component to ensure it is properly shared.
|
||||
*/
|
||||
@Injectable()
|
||||
export class OverlayContainer {
|
||||
export class OverlayContainer implements OnDestroy {
|
||||
protected _containerElement: HTMLElement;
|
||||
|
||||
private _themeClass: string;
|
||||
@@ -37,6 +37,12 @@ export class OverlayContainer {
|
||||
this._themeClass = value;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this._containerElement && this._containerElement.parentNode) {
|
||||
this._containerElement.parentNode.removeChild(this._containerElement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the overlay container element. It will lazily
|
||||
* create the element the first time it is called to facilitate using
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import {async, inject, TestBed} from '@angular/core/testing';
|
||||
import {Component, NgModule, ViewChild, ViewContainerRef} from '@angular/core';
|
||||
import {PortalModule, TemplatePortalDirective} from '../portal/portal-directives';
|
||||
import {Overlay, OverlayContainer, OverlayModule} from './index';
|
||||
|
||||
describe('OverlayContainer', () => {
|
||||
let overlay: Overlay;
|
||||
let overlayContainer: OverlayContainer;
|
||||
|
||||
beforeAll(() => {
|
||||
// Remove any stale overlay containers from previous tests that didn't clean up correctly.
|
||||
const staleContainers = document.querySelectorAll('.cdk-overlay-container');
|
||||
for (let i = staleContainers.length - 1; i >= 0; i--) {
|
||||
staleContainers[i].parentNode!.removeChild(staleContainers[i]);
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [OverlayTestModule]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(inject([Overlay, OverlayContainer], (o: Overlay, oc: OverlayContainer) => {
|
||||
overlay = o;
|
||||
overlayContainer = oc;
|
||||
}));
|
||||
|
||||
it('should remove the overlay container element from the DOM on destruction', () => {
|
||||
const fixture = TestBed.createComponent(TestComponentWithTemplatePortals);
|
||||
|
||||
const overlayRef = overlay.create();
|
||||
overlayRef.attach(fixture.componentInstance.templatePortal);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.querySelectorAll('.cdk-overlay-container'))
|
||||
.not.toBeNull('Expected the overlay container to be in the DOM after opening an overlay');
|
||||
|
||||
// Manually call `ngOnDestroy` because there is no way to force Angular to destroy an
|
||||
// injectable in a unit test.
|
||||
overlayContainer.ngOnDestroy();
|
||||
|
||||
expect(document.querySelector('.cdk-overlay-container'))
|
||||
.toBeNull('Expected the overlay container *not* to be in the DOM after destruction');
|
||||
});
|
||||
});
|
||||
|
||||
/** Test-bed component that contains a TempatePortal and an ElementRef. */
|
||||
@Component({
|
||||
template: `<ng-template cdk-portal>Cake</ng-template>`,
|
||||
providers: [Overlay],
|
||||
})
|
||||
class TestComponentWithTemplatePortals {
|
||||
@ViewChild(TemplatePortalDirective) templatePortal: TemplatePortalDirective;
|
||||
|
||||
constructor(public viewContainerRef: ViewContainerRef) { }
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [OverlayModule, PortalModule],
|
||||
declarations: [TestComponentWithTemplatePortals]
|
||||
})
|
||||
class OverlayTestModule { }
|
||||
Reference in New Issue
Block a user