66 * found in the LICENSE file at https://angular.io/license
77 */
88
9- import { coerceBooleanProperty } from '@angular/cdk/coercion' ;
9+ import { coerceBooleanProperty , coerceNumberProperty } from '@angular/cdk/coercion' ;
1010import {
1111 AfterContentInit ,
1212 Directive ,
@@ -16,12 +16,10 @@ import {
1616 Input ,
1717 NgModule ,
1818 NgZone ,
19- OnChanges ,
2019 OnDestroy ,
2120 Output ,
22- SimpleChanges ,
2321} from '@angular/core' ;
24- import { Subject } from 'rxjs' ;
22+ import { Observable , Subject } from 'rxjs' ;
2523import { debounceTime } from 'rxjs/operators' ;
2624
2725/**
@@ -35,6 +33,56 @@ export class MutationObserverFactory {
3533 }
3634}
3735
36+
37+ /** A factory that creates ContentObservers. */
38+ @Injectable ( { providedIn : 'root' } )
39+ export class ContentObserverFactory {
40+ constructor ( private _mutationObserverFactory : MutationObserverFactory , private _ngZone : NgZone ) { }
41+
42+ create ( element : Element , debounce ?: number ) {
43+ const changes = new Subject < MutationRecord [ ] > ( ) ;
44+ const observer = this . _ngZone . runOutsideAngular (
45+ ( ) => this . _mutationObserverFactory . create ( ( mutations ) => changes . next ( mutations ) ) ) ;
46+ return new ContentObserver ( element , observer , changes , debounce ) ;
47+ }
48+ }
49+
50+
51+ /** A class that observes an element for content changes. */
52+ export class ContentObserver {
53+ changes : Observable < MutationRecord [ ] > ;
54+
55+ constructor ( private _element : Element , private _mutationObserver : MutationObserver | null ,
56+ private _rawChanges : Subject < MutationRecord [ ] > , debounce : number = 0 ) {
57+ this . changes = debounce ?
58+ this . _rawChanges . pipe ( debounceTime ( debounce ) ) : this . _rawChanges . asObservable ( ) ;
59+ }
60+
61+ start ( ) : ContentObserver {
62+ if ( this . _mutationObserver ) {
63+ this . _mutationObserver . observe ( this . _element , {
64+ characterData : true ,
65+ childList : true ,
66+ subtree : true
67+ } ) ;
68+ }
69+ return this ;
70+ }
71+
72+ pause ( ) {
73+ if ( this . _mutationObserver ) {
74+ this . _mutationObserver . disconnect ( ) ;
75+ }
76+ }
77+
78+ stop ( ) {
79+ this . pause ( ) ;
80+ this . _rawChanges . complete ( ) ;
81+ this . _mutationObserver = null ;
82+ }
83+ }
84+
85+
3886/**
3987 * Directive that triggers a callback whenever the content of
4088 * its associated element has changed.
@@ -43,10 +91,7 @@ export class MutationObserverFactory {
4391 selector : '[cdkObserveContent]' ,
4492 exportAs : 'cdkObserveContent' ,
4593} )
46- export class CdkObserveContent implements AfterContentInit , OnChanges , OnDestroy {
47- private _observer : MutationObserver | null ;
48- private _disabled = false ;
49-
94+ export class CdkObserveContent implements AfterContentInit , OnDestroy {
5095 /** Event emitted for each change in the element's content. */
5196 @Output ( 'cdkObserveContent' ) event = new EventEmitter < MutationRecord [ ] > ( ) ;
5297
@@ -58,65 +103,42 @@ export class CdkObserveContent implements AfterContentInit, OnChanges, OnDestroy
58103 get disabled ( ) { return this . _disabled ; }
59104 set disabled ( value : any ) {
60105 this . _disabled = coerceBooleanProperty ( value ) ;
106+ if ( this . _observer ) {
107+ if ( this . _disabled ) {
108+ this . _observer . pause ( ) ;
109+ } else {
110+ this . _observer . start ( ) ;
111+ }
112+ }
61113 }
62-
63- /** Used for debouncing the emitted values to the observeContent event. */
64- private _debouncer = new Subject < MutationRecord [ ] > ( ) ;
114+ private _disabled = false ;
65115
66116 /** Debounce interval for emitting the changes. */
67- @Input ( ) debounce : number ;
117+ @Input ( )
118+ get debounce ( ) : number { return this . _debounce ; }
119+ set debounce ( value : number ) {
120+ this . _debounce = coerceNumberProperty ( value ) ;
121+ }
122+ private _debounce : number ;
68123
69- constructor (
70- private _mutationObserverFactory : MutationObserverFactory ,
71- private _elementRef : ElementRef ,
72- private _ngZone : NgZone ) { }
124+ private _observer : ContentObserver ;
73125
74- ngAfterContentInit ( ) {
75- if ( this . debounce > 0 ) {
76- this . _ngZone . runOutsideAngular ( ( ) => {
77- this . _debouncer . pipe ( debounceTime ( this . debounce ) )
78- . subscribe ( ( mutations : MutationRecord [ ] ) => this . event . emit ( mutations ) ) ;
79- } ) ;
80- } else {
81- this . _debouncer . subscribe ( mutations => this . event . emit ( mutations ) ) ;
82- }
126+ constructor ( private _contentObserverFactory : ContentObserverFactory ,
127+ private _elementRef : ElementRef , private _ngZone : NgZone ) { }
83128
84- this . _observer = this . _ngZone . runOutsideAngular ( ( ) => {
85- return this . _mutationObserverFactory . create ( ( mutations : MutationRecord [ ] ) => {
86- this . _debouncer . next ( mutations ) ;
87- } ) ;
88- } ) ;
129+ ngAfterContentInit ( ) {
130+ this . _observer =
131+ this . _contentObserverFactory . create ( this . _elementRef . nativeElement , this . debounce ) ;
132+ this . _ngZone . run (
133+ ( ) => this . _observer . changes . subscribe ( mutations => this . event . next ( mutations ) ) ) ;
89134
90135 if ( ! this . disabled ) {
91- this . _enable ( ) ;
92- }
93- }
94-
95- ngOnChanges ( changes : SimpleChanges ) {
96- if ( changes [ 'disabled' ] ) {
97- changes [ 'disabled' ] . currentValue ? this . _disable ( ) : this . _enable ( ) ;
136+ this . _observer . start ( ) ;
98137 }
99138 }
100139
101140 ngOnDestroy ( ) {
102- this . _disable ( ) ;
103- this . _debouncer . complete ( ) ;
104- }
105-
106- private _disable ( ) {
107- if ( this . _observer ) {
108- this . _observer . disconnect ( ) ;
109- }
110- }
111-
112- private _enable ( ) {
113- if ( this . _observer ) {
114- this . _observer . observe ( this . _elementRef . nativeElement , {
115- characterData : true ,
116- childList : true ,
117- subtree : true
118- } ) ;
119- }
141+ this . _observer . stop ( ) ;
120142 }
121143}
122144
0 commit comments