@@ -17,8 +17,8 @@ import {
1717 ViewChild ,
1818 ViewEncapsulation
1919} from '@angular/core' ;
20- import { BehaviorSubject , fromEvent , Observable } from 'rxjs' ;
21- import { filter , switchMap , take , takeUntil , withLatestFrom } from 'rxjs/operators' ;
20+ import { BehaviorSubject , EMPTY , from , fromEvent , Observable } from 'rxjs' ;
21+ import { switchMap , take , takeUntil , withLatestFrom } from 'rxjs/operators' ;
2222
2323import { NzDestroyService } from 'ng-zorro-antd/core/services' ;
2424import { NzTSType } from 'ng-zorro-antd/core/types' ;
@@ -66,9 +66,7 @@ export class NzTextEditComponent implements OnInit {
6666 @Output ( ) readonly endEditing = new EventEmitter < string > ( true ) ;
6767 @ViewChild ( 'textarea' , { static : false } )
6868 set textarea ( textarea : ElementRef < HTMLTextAreaElement > | undefined ) {
69- if ( textarea ) {
70- this . textarea$ . next ( textarea ) ;
71- }
69+ this . textarea$ . next ( textarea ) ;
7270 }
7371 @ViewChild ( NzAutosizeDirective , { static : false } ) autosizeDirective ! : NzAutosizeDirective ;
7472
@@ -79,7 +77,7 @@ export class NzTextEditComponent implements OnInit {
7977 // We could've saved the textarea within some private property (e.g. `_textarea`) and have a getter,
8078 // but having subject makes the code more reactive and cancellable (e.g. event listeners will be
8179 // automatically removed and re-added through the `switchMap` below).
82- private textarea$ = new BehaviorSubject < ElementRef < HTMLTextAreaElement > | null > ( null ) ;
80+ private textarea$ = new BehaviorSubject < ElementRef < HTMLTextAreaElement > | null | undefined > ( null ) ;
8381
8482 constructor (
8583 private ngZone : NgZone ,
@@ -95,22 +93,19 @@ export class NzTextEditComponent implements OnInit {
9593 this . cdr . markForCheck ( ) ;
9694 } ) ;
9795
98- const textarea$ : Observable < ElementRef < HTMLTextAreaElement > > = this . textarea$ . pipe (
99- filter ( ( textarea ) : textarea is ElementRef < HTMLTextAreaElement > => textarea !== null )
100- ) ;
101-
102- textarea$
96+ this . textarea$
10397 . pipe (
104- switchMap (
105- textarea =>
106- // Caretaker note: we explicitly should call `subscribe()` within the root zone.
107- // `runOutsideAngular(() => fromEvent(...))` will just create an observable within the root zone,
108- // but `addEventListener` is called when the `fromEvent` is subscribed.
109- new Observable < KeyboardEvent > ( subscriber =>
110- this . ngZone . runOutsideAngular ( ( ) =>
111- fromEvent < KeyboardEvent > ( textarea . nativeElement , 'keydown' ) . subscribe ( subscriber )
98+ switchMap ( textarea =>
99+ // Caretaker note: we explicitly should call `subscribe()` within the root zone.
100+ // `runOutsideAngular(() => fromEvent(...))` will just create an observable within the root zone,
101+ // but `addEventListener` is called when the `fromEvent` is subscribed.
102+ textarea
103+ ? new Observable < KeyboardEvent > ( subscriber =>
104+ this . ngZone . runOutsideAngular ( ( ) =>
105+ fromEvent < KeyboardEvent > ( textarea . nativeElement , 'keydown' ) . subscribe ( subscriber )
106+ )
112107 )
113- )
108+ : EMPTY
114109 ) ,
115110 takeUntil ( this . destroy$ )
116111 )
@@ -133,15 +128,16 @@ export class NzTextEditComponent implements OnInit {
133128 } ) ;
134129 } ) ;
135130
136- textarea$
131+ this . textarea$
137132 . pipe (
138- switchMap (
139- textarea =>
140- new Observable < KeyboardEvent > ( subscriber =>
141- this . ngZone . runOutsideAngular ( ( ) =>
142- fromEvent < KeyboardEvent > ( textarea . nativeElement , 'input' ) . subscribe ( subscriber )
133+ switchMap ( textarea =>
134+ textarea
135+ ? new Observable < KeyboardEvent > ( subscriber =>
136+ this . ngZone . runOutsideAngular ( ( ) =>
137+ fromEvent < KeyboardEvent > ( textarea . nativeElement , 'input' ) . subscribe ( subscriber )
138+ )
143139 )
144- )
140+ : EMPTY
145141 ) ,
146142 takeUntil ( this . destroy$ )
147143 )
@@ -175,15 +171,20 @@ export class NzTextEditComponent implements OnInit {
175171 }
176172
177173 focusAndSetValue ( ) : void {
178- this . ngZone . onStable
179- . pipe ( take ( 1 ) , withLatestFrom ( this . textarea$ ) , takeUntil ( this . destroy$ ) )
180- . subscribe ( ( [ , textarea ] ) => {
174+ // Note: the zone may be nooped through `BootstrapOptions` when bootstrapping the root module. This means
175+ // the `onStable` will never emit any value.
176+ const onStable$ = this . ngZone . isStable ? from ( Promise . resolve ( ) ) : this . ngZone . onStable . pipe ( take ( 1 ) ) ;
177+ // Normally this isn't in the zone, but it can cause performance regressions for apps
178+ // using `zone-patch-rxjs` because it'll trigger a change detection when it unsubscribes.
179+ this . ngZone . runOutsideAngular ( ( ) => {
180+ onStable$ . pipe ( withLatestFrom ( this . textarea$ ) , takeUntil ( this . destroy$ ) ) . subscribe ( ( [ , textarea ] ) => {
181181 if ( textarea ) {
182182 textarea . nativeElement . focus ( ) ;
183183 textarea . nativeElement . value = this . currentText || '' ;
184184 this . autosizeDirective . resizeToFitContent ( ) ;
185185 this . cdr . markForCheck ( ) ;
186186 }
187187 } ) ;
188+ } ) ;
188189 }
189190}
0 commit comments