Skip to content

Commit 37193d8

Browse files
mmalerbajosephperrott
authored andcommitted
fix(focus-monitor): reenter ngzone before emitting (#10549)
1 parent 01ec602 commit 37193d8

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

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

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
dispatchMouseEvent,
66
patchElementFocus,
77
} from '@angular/cdk/testing';
8-
import {Component} from '@angular/core';
8+
import {Component, NgZone} from '@angular/core';
99
import {ComponentFixture, fakeAsync, flush, inject, TestBed, tick} from '@angular/core/testing';
1010
import {By} from '@angular/platform-browser';
1111
import {A11yModule} from '../index';
@@ -212,7 +212,6 @@ describe('FocusMonitor', () => {
212212

213213
expect(buttonElement.classList.length).toBe(0, 'button should not have any focus classes');
214214
}));
215-
216215
});
217216

218217

@@ -224,7 +223,7 @@ describe('cdkMonitorFocus', () => {
224223
ButtonWithFocusClasses,
225224
ComplexComponentWithMonitorElementFocus,
226225
ComplexComponentWithMonitorSubtreeFocus,
227-
ComplexComponentWithMonitorSubtreeFocusAnfMonitorElementFocus,
226+
ComplexComponentWithMonitorSubtreeFocusAndMonitorElementFocus,
228227
],
229228
}).compileComponents();
230229
});
@@ -394,15 +393,15 @@ describe('cdkMonitorFocus', () => {
394393
});
395394

396395
describe('complex component with cdkMonitorSubtreeFocus and cdkMonitorElementFocus', () => {
397-
let fixture: ComponentFixture<ComplexComponentWithMonitorSubtreeFocusAnfMonitorElementFocus>;
396+
let fixture: ComponentFixture<ComplexComponentWithMonitorSubtreeFocusAndMonitorElementFocus>;
398397
let parentElement: HTMLElement;
399398
let childElement: HTMLElement;
400399
let focusMonitor: FocusMonitor;
401400

402401
beforeEach(inject([FocusMonitor], (fm: FocusMonitor) => {
403402
focusMonitor = fm;
404403
fixture =
405-
TestBed.createComponent(ComplexComponentWithMonitorSubtreeFocusAnfMonitorElementFocus);
404+
TestBed.createComponent(ComplexComponentWithMonitorSubtreeFocusAndMonitorElementFocus);
406405
fixture.detectChanges();
407406

408407
parentElement = fixture.debugElement.query(By.css('div')).nativeElement;
@@ -424,6 +423,40 @@ describe('cdkMonitorFocus', () => {
424423
});
425424
});
426425

426+
describe('FocusMonitor observable stream', () => {
427+
let fixture: ComponentFixture<PlainButton>;
428+
let buttonElement: HTMLElement;
429+
let focusMonitor: FocusMonitor;
430+
431+
beforeEach(() => {
432+
TestBed.configureTestingModule({
433+
imports: [A11yModule],
434+
declarations: [
435+
PlainButton,
436+
],
437+
}).compileComponents();
438+
});
439+
440+
beforeEach(inject([FocusMonitor], (fm: FocusMonitor) => {
441+
fixture = TestBed.createComponent(PlainButton);
442+
focusMonitor = fm;
443+
fixture.detectChanges();
444+
buttonElement = fixture.debugElement.nativeElement.querySelector('button');
445+
patchElementFocus(buttonElement);
446+
}));
447+
448+
it('should emit inside the NgZone', fakeAsync(() => {
449+
const spy = jasmine.createSpy('zone spy');
450+
focusMonitor.monitor(buttonElement).subscribe(() => spy(NgZone.isInAngularZone()));
451+
expect(spy).not.toHaveBeenCalled();
452+
453+
buttonElement.focus();
454+
fixture.detectChanges();
455+
tick();
456+
expect(spy).toHaveBeenCalledWith(true);
457+
}));
458+
});
459+
427460

428461
@Component({
429462
template: `<button>focus me!</button>`
@@ -453,4 +486,4 @@ class ComplexComponentWithMonitorSubtreeFocus {}
453486
@Component({
454487
template: `<div cdkMonitorSubtreeFocus><button cdkMonitorElementFocus></button></div>`
455488
})
456-
class ComplexComponentWithMonitorSubtreeFocusAnfMonitorElementFocus {}
489+
class ComplexComponentWithMonitorSubtreeFocusAndMonitorElementFocus {}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ export class FocusMonitor implements OnDestroy {
314314
}
315315

316316
this._setClasses(element, origin);
317-
elementInfo.subject.next(origin);
317+
this._emitOrigin(elementInfo.subject, origin);
318318
this._lastFocusOrigin = origin;
319319
}
320320

@@ -334,7 +334,11 @@ export class FocusMonitor implements OnDestroy {
334334
}
335335

336336
this._setClasses(element);
337-
elementInfo.subject.next(null);
337+
this._emitOrigin(elementInfo.subject, null);
338+
}
339+
340+
private _emitOrigin(subject: Subject<FocusOrigin>, origin: FocusOrigin) {
341+
this._ngZone.run(() => subject.next(origin));
338342
}
339343

340344
private _incrementMonitoredElementCount() {

0 commit comments

Comments
 (0)