@@ -33,9 +33,10 @@ export class MutationObserverFactory {
33
33
}
34
34
35
35
36
- /** A factory that creates ContentObservers . */
36
+ /** An injectable service that allows watching elements for changes to their content . */
37
37
@Injectable ( { providedIn : 'root' } )
38
- export class ContentObserver {
38
+ export class ContentObserver implements OnDestroy {
39
+ /** Keeps track of the existing MutationObservers so they can be reused. */
39
40
private _observedElements = new Map < Element , {
40
41
observer : MutationObserver | null ,
41
42
stream : Subject < MutationRecord [ ] > ,
@@ -44,19 +45,30 @@ export class ContentObserver {
44
45
45
46
constructor ( private _mutationObserverFactory : MutationObserverFactory ) { }
46
47
47
- observe ( element : Element , debounce ?: number ) : Observable < MutationRecord [ ] > {
48
+ ngOnDestroy ( ) {
49
+ this . _observedElements . forEach ( ( _ , element ) => this . _cleanupObserver ( element ) ) ;
50
+ }
51
+
52
+ /**
53
+ * Observe content changes on an element.
54
+ * @param element The element to observe for content changes.
55
+ */
56
+ observe ( element : Element ) : Observable < MutationRecord [ ] > {
48
57
return Observable . create ( observer => {
49
58
const stream = this . _observeElement ( element ) ;
50
- const subscription =
51
- ( debounce ? stream . pipe ( debounceTime ( debounce ) ) : stream ) . subscribe ( observer ) ;
59
+ const subscription = stream . subscribe ( observer ) ;
52
60
53
61
return ( ) => {
54
62
subscription . unsubscribe ( ) ;
55
63
this . _unobserveElement ( element ) ;
56
- }
64
+ } ;
57
65
} ) ;
58
66
}
59
67
68
+ /**
69
+ * Observes the given element by using the existing MutationObserver if available, or creating a
70
+ * new one if not.
71
+ */
60
72
private _observeElement ( element : Element ) : Subject < MutationRecord [ ] > {
61
73
if ( ! this . _observedElements . has ( element ) ) {
62
74
const stream = new Subject < MutationRecord [ ] > ( ) ;
@@ -75,14 +87,20 @@ export class ContentObserver {
75
87
return this . _observedElements . get ( element ) ! . stream ;
76
88
}
77
89
90
+ /**
91
+ * Un-observes the given element and cleans up the underlying MutationObserver if nobody else is
92
+ * observing this element.
93
+ */
78
94
private _unobserveElement ( element : Element ) {
79
95
if ( this . _observedElements . has ( element ) ) {
80
- if ( ! -- this . _observedElements . get ( element ) ! . count ) {
96
+ this . _observedElements . get ( element ) ! . count -- ;
97
+ if ( ! this . _observedElements . get ( element ) ! . count ) {
81
98
this . _cleanupObserver ( element ) ;
82
99
}
83
100
}
84
101
}
85
102
103
+ /** Clean up the underlying MutationObserver for the specified element. */
86
104
private _cleanupObserver ( element : Element ) {
87
105
if ( this . _observedElements . has ( element ) ) {
88
106
const { observer, stream} = this . _observedElements . get ( element ) ! ;
@@ -149,9 +167,9 @@ export class CdkObserveContent implements AfterContentInit, OnDestroy {
149
167
150
168
private _subscribe ( ) {
151
169
this . _unsubscribe ( ) ;
152
- this . _currentSubscription =
153
- this . _contentObserver . observe ( this . _elementRef . nativeElement , this . debounce )
154
- . subscribe ( mutations => this . event . next ( mutations ) ) ;
170
+ const stream = this . _contentObserver . observe ( this . _elementRef . nativeElement ) ;
171
+ this . _currentSubscription = ( this . debounce ? stream . pipe ( debounceTime ( this . debounce ) ) : stream )
172
+ . subscribe ( mutations => this . event . next ( mutations ) ) ;
155
173
}
156
174
157
175
private _unsubscribe ( ) {
0 commit comments