Skip to content

Commit 0550aec

Browse files
committed
fix(overlay): disposed overlays not removed from the key event stack
Fixes overlays that are removed via `dispose` without being `detached` first not being removed from the stack inside the `OverlayKeyboardDispatcher`, causing them to block events for any subsequent overlays.
1 parent 541a95e commit 0550aec

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

src/cdk/overlay/keyboard/overlay-keyboard-dispatcher.spec.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import {TestBed, inject} from '@angular/core/testing';
22
import {dispatchKeyboardEvent} from '@angular/cdk/testing';
33
import {ESCAPE} from '@angular/cdk/keycodes';
4+
import {Component, NgModule} from '@angular/core';
45
import {Overlay} from '../overlay';
56
import {OverlayContainer} from '../overlay-container';
67
import {OverlayModule} from '../index';
78
import {OverlayKeyboardDispatcher} from './overlay-keyboard-dispatcher';
9+
import {ComponentPortal} from '@angular/cdk/portal';
10+
811

912
describe('OverlayKeyboardDispatcher', () => {
1013
let keyboardDispatcher: OverlayKeyboardDispatcher;
@@ -13,7 +16,7 @@ describe('OverlayKeyboardDispatcher', () => {
1316

1417
beforeEach(() => {
1518
TestBed.configureTestingModule({
16-
imports: [OverlayModule],
19+
imports: [OverlayModule, TestComponentModule],
1720
providers: [
1821
{provide: OverlayContainer, useFactory: () => {
1922
overlayContainerElement = document.createElement('div');
@@ -94,4 +97,52 @@ describe('OverlayKeyboardDispatcher', () => {
9497
expect(overlayTwoSpy).not.toHaveBeenCalled();
9598
});
9699

100+
it('should stop emitting events to detached overlays', () => {
101+
const instance = overlay.create();
102+
const spy = jasmine.createSpy('keyboard event spy');
103+
104+
instance.attach(new ComponentPortal(TestComponent));
105+
instance.keydownEvents().subscribe(spy);
106+
107+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, instance.overlayElement);
108+
expect(spy).toHaveBeenCalledTimes(1);
109+
110+
instance.detach();
111+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, instance.overlayElement);
112+
113+
expect(spy).toHaveBeenCalledTimes(1);
114+
});
115+
116+
it('should stop emitting events to disposed overlays', () => {
117+
const instance = overlay.create();
118+
const spy = jasmine.createSpy('keyboard event spy');
119+
120+
instance.attach(new ComponentPortal(TestComponent));
121+
instance.keydownEvents().subscribe(spy);
122+
123+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, instance.overlayElement);
124+
expect(spy).toHaveBeenCalledTimes(1);
125+
126+
instance.dispose();
127+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, instance.overlayElement);
128+
129+
expect(spy).toHaveBeenCalledTimes(1);
130+
});
131+
97132
});
133+
134+
135+
@Component({
136+
template: 'Hello'
137+
})
138+
class TestComponent { }
139+
140+
141+
// Create a real (non-test) NgModule as a workaround for
142+
// https://github.com/angular/angular/issues/10760
143+
@NgModule({
144+
exports: [TestComponent],
145+
declarations: [TestComponent],
146+
entryComponents: [TestComponent],
147+
})
148+
class TestComponentModule { }

src/cdk/overlay/overlay-ref.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export class OverlayRef implements PortalOutlet {
148148
}
149149

150150
this.detachBackdrop();
151+
this._keyboardDispatcher.remove(this);
151152
this._portalOutlet.dispose();
152153
this._attachments.complete();
153154
this._backdropClick.complete();

0 commit comments

Comments
 (0)