Skip to content

Commit bba3f07

Browse files
committed
refactor(live-announcer): run outside NgZone
Switches to running the timeout from the `LiveAnnouncer` outside the `NgZone`, because it does all of its DOM manipulation directly on the element and it doesn't have to trigger Angular's change detection.
1 parent dcd2282 commit bba3f07

File tree

1 file changed

+12
-8
lines changed

1 file changed

+12
-8
lines changed

src/cdk/a11y/live-announcer/live-announcer.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class LiveAnnouncer implements OnDestroy {
3434

3535
constructor(
3636
@Optional() @Inject(LIVE_ANNOUNCER_ELEMENT_TOKEN) elementToken: any,
37+
private _ngZone: NgZone,
3738
@Inject(DOCUMENT) _document: any) {
3839

3940
// We inject the live element and document as `any` because the constructor signature cannot
@@ -60,11 +61,13 @@ export class LiveAnnouncer implements OnDestroy {
6061
// - With Chrome and IE11 with NVDA or JAWS, a repeated (identical) message won't be read a
6162
// second time without clearing and then using a non-zero delay.
6263
// (using JAWS 17 at time of this writing).
63-
return new Promise(resolve => {
64-
setTimeout(() => {
65-
this._liveElement.textContent = message;
66-
resolve();
67-
}, 100);
64+
return this._ngZone.runOutsideAngular(() => {
65+
return new Promise(resolve => {
66+
setTimeout(() => {
67+
this._liveElement.textContent = message;
68+
resolve();
69+
}, 100);
70+
});
6871
});
6972
}
7073

@@ -77,13 +80,13 @@ export class LiveAnnouncer implements OnDestroy {
7780
private _createLiveElement(): HTMLElement {
7881
const elementClass = 'cdk-live-announcer-element';
7982
const previousElements = this._document.getElementsByClassName(elementClass);
83+
const liveEl = this._document.createElement('div');
8084

8185
// Remove any old containers. This can happen when coming in from a server-side-rendered page.
8286
for (let i = 0; i < previousElements.length; i++) {
8387
previousElements[i].parentNode!.removeChild(previousElements[i]);
8488
}
8589

86-
const liveEl = this._document.createElement('div');
8790
liveEl.classList.add(elementClass);
8891
liveEl.classList.add('cdk-visually-hidden');
8992

@@ -143,8 +146,8 @@ export class CdkAriaLive implements OnDestroy {
143146

144147
/** @docs-private @deprecated @breaking-change 7.0.0 */
145148
export function LIVE_ANNOUNCER_PROVIDER_FACTORY(
146-
parentDispatcher: LiveAnnouncer, liveElement: any, _document: any) {
147-
return parentDispatcher || new LiveAnnouncer(liveElement, _document);
149+
parentDispatcher: LiveAnnouncer, liveElement: any, _document: any, ngZone: NgZone) {
150+
return parentDispatcher || new LiveAnnouncer(liveElement, _document, ngZone);
148151
}
149152

150153

@@ -156,6 +159,7 @@ export const LIVE_ANNOUNCER_PROVIDER: Provider = {
156159
[new Optional(), new SkipSelf(), LiveAnnouncer],
157160
[new Optional(), new Inject(LIVE_ANNOUNCER_ELEMENT_TOKEN)],
158161
DOCUMENT,
162+
NgZone,
159163
],
160164
useFactory: LIVE_ANNOUNCER_PROVIDER_FACTORY
161165
};

0 commit comments

Comments
 (0)