Skip to content

Commit cc52d61

Browse files
authored
fix(cdk/a11y): don't emit blurred events on the server (#27315)
The `FocusMonitor` is set up to emit `null` when an element is blurred and we have some components that depend on that value to mark themselves as touched. However, it's also set up to return an rxjs observale `of(null)` on the server which means that it'll emit and complete immediately. This is problematic, because it can mark components as touched even though they haven't been. These changes remove the parameter from `of()` so it never emits. Fixes #27234.
1 parent 840878f commit cc52d61

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {DOCUMENT} from '@angular/common';
1111
import {Component, NgZone, ViewChild} from '@angular/core';
1212
import {ComponentFixture, fakeAsync, flush, inject, TestBed, tick} from '@angular/core/testing';
1313
import {By} from '@angular/platform-browser';
14+
import {Platform} from '@angular/cdk/platform';
1415
import {A11yModule, CdkMonitorFocus} from '../index';
1516
import {TOUCH_BUFFER_MS} from '../input-modality/input-modality-detector';
1617
import {
@@ -824,11 +825,14 @@ describe('FocusMonitor observable stream', () => {
824825
let fixture: ComponentFixture<PlainButton>;
825826
let buttonElement: HTMLElement;
826827
let focusMonitor: FocusMonitor;
828+
let fakePlatform: Platform;
827829

828830
beforeEach(() => {
831+
fakePlatform = {isBrowser: true} as Platform;
829832
TestBed.configureTestingModule({
830833
imports: [A11yModule],
831834
declarations: [PlainButton],
835+
providers: [{provide: Platform, useValue: fakePlatform}],
832836
}).compileComponents();
833837
});
834838

@@ -850,6 +854,22 @@ describe('FocusMonitor observable stream', () => {
850854
tick();
851855
expect(spy).toHaveBeenCalledWith(true);
852856
}));
857+
858+
it('should not emit on the server', fakeAsync(() => {
859+
fakePlatform.isBrowser = false;
860+
const emitSpy = jasmine.createSpy('emit spy');
861+
const completeSpy = jasmine.createSpy('complete spy');
862+
863+
focusMonitor.monitor(buttonElement).subscribe({next: emitSpy, complete: completeSpy});
864+
expect(emitSpy).not.toHaveBeenCalled();
865+
expect(completeSpy).toHaveBeenCalled();
866+
867+
buttonElement.focus();
868+
fixture.detectChanges();
869+
tick();
870+
expect(emitSpy).not.toHaveBeenCalled();
871+
expect(completeSpy).toHaveBeenCalled();
872+
}));
853873
});
854874

855875
describe('FocusMonitor input label detection', () => {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ export class FocusMonitor implements OnDestroy {
197197

198198
// Do nothing if we're not on the browser platform or the passed in node isn't an element.
199199
if (!this._platform.isBrowser || nativeElement.nodeType !== 1) {
200-
return observableOf(null);
200+
// Note: we don't want the observable to emit at all so we don't pass any parameters.
201+
return observableOf();
201202
}
202203

203204
// If the element is inside the shadow DOM, we need to bind our focus/blur listeners to

0 commit comments

Comments
 (0)