Skip to content

Commit 8972bf4

Browse files
crisbetojelbourn
authored andcommitted
fix(focus-monitor): implement OnDestroy logic (#9305)
Similarly to most of the other DOM-related services, these changes implement `ngOnDestroy` for the `FocusMonitor` which removes the monitoring from all of the currently-monitored elements.
1 parent c604834 commit 8972bf4

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

src/cdk/a11y/focus-monitor.spec.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,28 @@ describe('FocusMonitor', () => {
186186
fixture.detectChanges();
187187
tick();
188188

189-
expect(buttonElement.classList.length)
190-
.toBe(2, 'button should have exactly 2 focus classes');
189+
expect(buttonElement.classList.length).toBe(2, 'button should have exactly 2 focus classes');
191190

192191
focusMonitor.stopMonitoring(buttonElement);
193192
fixture.detectChanges();
194193

195194
expect(buttonElement.classList.length).toBe(0, 'button should not have any focus classes');
196195
}));
196+
197+
it('should remove classes when destroyed', fakeAsync(() => {
198+
buttonElement.focus();
199+
fixture.detectChanges();
200+
tick();
201+
202+
expect(buttonElement.classList.length).toBe(2, 'button should have exactly 2 focus classes');
203+
204+
// Destroy manually since destroying the fixture won't do it.
205+
focusMonitor.ngOnDestroy();
206+
fixture.detectChanges();
207+
208+
expect(buttonElement.classList.length).toBe(0, 'button should not have any focus classes');
209+
}));
210+
197211
});
198212

199213

src/cdk/a11y/focus-monitor.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type MonitoredElementInfo = {
4242

4343
/** Monitors mouse and keyboard events to determine the cause of focus events. */
4444
@Injectable()
45-
export class FocusMonitor {
45+
export class FocusMonitor implements OnDestroy {
4646
/** The focus origin that the next focus event is a result of. */
4747
private _origin: FocusOrigin = null;
4848

@@ -58,8 +58,8 @@ export class FocusMonitor {
5858
/** The timeout id of the touch timeout, used to cancel timeout later. */
5959
private _touchTimeout: number;
6060

61-
/** Weak map of elements being monitored to their info. */
62-
private _elementInfo = new WeakMap<Element, MonitoredElementInfo>();
61+
/** Map of elements being monitored to their info. */
62+
private _elementInfo = new Map<HTMLElement, MonitoredElementInfo>();
6363

6464
/** A map of global objects to lists of current listeners. */
6565
private _unregisterGlobalListeners = () => {};
@@ -135,7 +135,7 @@ export class FocusMonitor {
135135
* @param element The element to stop monitoring.
136136
*/
137137
stopMonitoring(element: HTMLElement): void {
138-
let elementInfo = this._elementInfo.get(element);
138+
const elementInfo = this._elementInfo.get(element);
139139

140140
if (elementInfo) {
141141
elementInfo.unlisten();
@@ -157,6 +157,10 @@ export class FocusMonitor {
157157
element.focus();
158158
}
159159

160+
ngOnDestroy() {
161+
this._elementInfo.forEach((_info, element) => this.stopMonitoring(element));
162+
}
163+
160164
/** Register necessary event listeners on the document and window. */
161165
private _registerGlobalListeners() {
162166
// Do nothing if we're not on the browser platform.

0 commit comments

Comments
 (0)