Skip to content

Commit 461dfaf

Browse files
crisbetojelbourn
authored andcommitted
fix(overlay): disposed overlays not removed from the key event stack (#8226)
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 bd26e2a commit 461dfaf

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');
@@ -105,4 +108,52 @@ describe('OverlayKeyboardDispatcher', () => {
105108
expect(completeSpy).toHaveBeenCalled();
106109
});
107110

111+
it('should stop emitting events to detached overlays', () => {
112+
const instance = overlay.create();
113+
const spy = jasmine.createSpy('keyboard event spy');
114+
115+
instance.attach(new ComponentPortal(TestComponent));
116+
instance.keydownEvents().subscribe(spy);
117+
118+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, instance.overlayElement);
119+
expect(spy).toHaveBeenCalledTimes(1);
120+
121+
instance.detach();
122+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, instance.overlayElement);
123+
124+
expect(spy).toHaveBeenCalledTimes(1);
125+
});
126+
127+
it('should stop emitting events to disposed overlays', () => {
128+
const instance = overlay.create();
129+
const spy = jasmine.createSpy('keyboard event spy');
130+
131+
instance.attach(new ComponentPortal(TestComponent));
132+
instance.keydownEvents().subscribe(spy);
133+
134+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, instance.overlayElement);
135+
expect(spy).toHaveBeenCalledTimes(1);
136+
137+
instance.dispose();
138+
dispatchKeyboardEvent(document.body, 'keydown', ESCAPE, instance.overlayElement);
139+
140+
expect(spy).toHaveBeenCalledTimes(1);
141+
});
142+
108143
});
144+
145+
146+
@Component({
147+
template: 'Hello'
148+
})
149+
class TestComponent { }
150+
151+
152+
// Create a real (non-test) NgModule as a workaround for
153+
// https://github.com/angular/angular/issues/10760
154+
@NgModule({
155+
exports: [TestComponent],
156+
declarations: [TestComponent],
157+
entryComponents: [TestComponent],
158+
})
159+
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)