Skip to content

Commit 81fe8f3

Browse files
authored
fix(cdk/observers): Run content changed callback in NgZone (#28870)
* fix(cdk/observers): Run content changed callback in NgZone * fixup! fix(cdk/observers): Run content changed callback in NgZone
1 parent 9381f90 commit 81fe8f3

File tree

2 files changed

+28
-27
lines changed

2 files changed

+28
-27
lines changed

src/cdk/observers/observe-content.ts

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
OnDestroy,
2020
Output,
2121
booleanAttribute,
22+
inject,
2223
} from '@angular/core';
2324
import {Observable, Observer, Subject, Subscription} from 'rxjs';
2425
import {debounceTime, filter, map} from 'rxjs/operators';
@@ -74,6 +75,8 @@ export class ContentObserver implements OnDestroy {
7475
}
7576
>();
7677

78+
private _ngZone = inject(NgZone);
79+
7780
constructor(private _mutationObserverFactory: MutationObserverFactory) {}
7881

7982
ngOnDestroy() {
@@ -102,7 +105,11 @@ export class ContentObserver implements OnDestroy {
102105
map(records => records.filter(record => !shouldIgnoreRecord(record))),
103106
filter(records => !!records.length),
104107
)
105-
.subscribe(observer);
108+
.subscribe(records => {
109+
this._ngZone.run(() => {
110+
observer.next(records);
111+
});
112+
});
106113

107114
return () => {
108115
subscription.unsubscribe();
@@ -116,21 +123,23 @@ export class ContentObserver implements OnDestroy {
116123
* new one if not.
117124
*/
118125
private _observeElement(element: Element): Subject<MutationRecord[]> {
119-
if (!this._observedElements.has(element)) {
120-
const stream = new Subject<MutationRecord[]>();
121-
const observer = this._mutationObserverFactory.create(mutations => stream.next(mutations));
122-
if (observer) {
123-
observer.observe(element, {
124-
characterData: true,
125-
childList: true,
126-
subtree: true,
127-
});
126+
return this._ngZone.runOutsideAngular(() => {
127+
if (!this._observedElements.has(element)) {
128+
const stream = new Subject<MutationRecord[]>();
129+
const observer = this._mutationObserverFactory.create(mutations => stream.next(mutations));
130+
if (observer) {
131+
observer.observe(element, {
132+
characterData: true,
133+
childList: true,
134+
subtree: true,
135+
});
136+
}
137+
this._observedElements.set(element, {observer, stream, count: 1});
138+
} else {
139+
this._observedElements.get(element)!.count++;
128140
}
129-
this._observedElements.set(element, {observer, stream, count: 1});
130-
} else {
131-
this._observedElements.get(element)!.count++;
132-
}
133-
return this._observedElements.get(element)!.stream;
141+
return this._observedElements.get(element)!.stream;
142+
});
134143
}
135144

136145
/**
@@ -202,7 +211,6 @@ export class CdkObserveContent implements AfterContentInit, OnDestroy {
202211
constructor(
203212
private _contentObserver: ContentObserver,
204213
private _elementRef: ElementRef<HTMLElement>,
205-
private _ngZone: NgZone,
206214
) {}
207215

208216
ngAfterContentInit() {
@@ -219,15 +227,9 @@ export class CdkObserveContent implements AfterContentInit, OnDestroy {
219227
this._unsubscribe();
220228
const stream = this._contentObserver.observe(this._elementRef);
221229

222-
// TODO(mmalerba): We shouldn't be emitting on this @Output() outside the zone.
223-
// Consider brining it back inside the zone next time we're making breaking changes.
224-
// Bringing it back inside can cause things like infinite change detection loops and changed
225-
// after checked errors if people's code isn't handling it properly.
226-
this._ngZone.runOutsideAngular(() => {
227-
this._currentSubscription = (
228-
this.debounce ? stream.pipe(debounceTime(this.debounce)) : stream
229-
).subscribe(this.event);
230-
});
230+
this._currentSubscription = (
231+
this.debounce ? stream.pipe(debounceTime(this.debounce)) : stream
232+
).subscribe(this.event);
231233
}
232234

233235
private _unsubscribe() {

tools/public_api_guard/cdk/observers.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ import { AfterContentInit } from '@angular/core';
88
import { ElementRef } from '@angular/core';
99
import { EventEmitter } from '@angular/core';
1010
import * as i0 from '@angular/core';
11-
import { NgZone } from '@angular/core';
1211
import { NumberInput } from '@angular/cdk/coercion';
1312
import { Observable } from 'rxjs';
1413
import { OnDestroy } from '@angular/core';
1514

1615
// @public
1716
export class CdkObserveContent implements AfterContentInit, OnDestroy {
18-
constructor(_contentObserver: ContentObserver, _elementRef: ElementRef<HTMLElement>, _ngZone: NgZone);
17+
constructor(_contentObserver: ContentObserver, _elementRef: ElementRef<HTMLElement>);
1918
get debounce(): number;
2019
set debounce(value: NumberInput);
2120
get disabled(): boolean;

0 commit comments

Comments
 (0)