@@ -274,51 +274,24 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
274
274
}
275
275
276
276
ngAfterViewInit ( ) {
277
- // We need to wait for the zone to stabilize, in order for the reference
278
- // element to be in the proper place in the DOM. This is mostly relevant
279
- // for draggable elements inside portals since they get stamped out in
280
- // their original DOM position and then they get transferred to the portal.
281
- this . _ngZone . onStable
282
- . pipe ( take ( 1 ) , takeUntil ( this . _destroyed ) )
283
- . subscribe ( ( ) => {
284
- this . _updateRootElement ( ) ;
285
-
286
- // Listen for any newly-added handles.
287
- this . _handles . changes . pipe (
288
- startWith ( this . _handles ) ,
289
- // Sync the new handles with the DragRef.
290
- tap ( ( handles : QueryList < CdkDragHandle > ) => {
291
- const childHandleElements = handles
292
- . filter ( handle => handle . _parentDrag === this )
293
- . map ( handle => handle . element ) ;
294
-
295
- // Usually handles are only allowed to be a descendant of the drag element, but if
296
- // the consumer defined a different drag root, we should allow the drag element
297
- // itself to be a handle too.
298
- if ( this . _selfHandle && this . rootElementSelector ) {
299
- childHandleElements . push ( this . element ) ;
300
- }
301
-
302
- this . _dragRef . withHandles ( childHandleElements ) ;
303
- } ) ,
304
- // Listen if the state of any of the handles changes.
305
- switchMap ( ( handles : QueryList < CdkDragHandle > ) => {
306
- return merge ( ...handles . map ( item => {
307
- return item . _stateChanges . pipe ( startWith ( item ) ) ;
308
- } ) ) as Observable < CdkDragHandle > ;
309
- } ) ,
310
- takeUntil ( this . _destroyed )
311
- ) . subscribe ( handleInstance => {
312
- // Enabled/disable the handle that changed in the DragRef.
313
- const dragRef = this . _dragRef ;
314
- const handle = handleInstance . element . nativeElement ;
315
- handleInstance . disabled ? dragRef . disableHandle ( handle ) : dragRef . enableHandle ( handle ) ;
277
+ // Normally this isn't in the zone, but it can cause major performance regressions for apps
278
+ // using `zone-patch-rxjs` because it'll trigger a change detection when it unsubscribes.
279
+ this . _ngZone . runOutsideAngular ( ( ) => {
280
+ // We need to wait for the zone to stabilize, in order for the reference
281
+ // element to be in the proper place in the DOM. This is mostly relevant
282
+ // for draggable elements inside portals since they get stamped out in
283
+ // their original DOM position and then they get transferred to the portal.
284
+ this . _ngZone . onStable
285
+ . pipe ( take ( 1 ) , takeUntil ( this . _destroyed ) )
286
+ . subscribe ( ( ) => {
287
+ this . _updateRootElement ( ) ;
288
+ this . _setupHandlesListener ( ) ;
289
+
290
+ if ( this . freeDragPosition ) {
291
+ this . _dragRef . setFreeDragPosition ( this . freeDragPosition ) ;
292
+ }
316
293
} ) ;
317
-
318
- if ( this . freeDragPosition ) {
319
- this . _dragRef . setFreeDragPosition ( this . freeDragPosition ) ;
320
- }
321
- } ) ;
294
+ } ) ;
322
295
}
323
296
324
297
ngOnChanges ( changes : SimpleChanges ) {
@@ -346,9 +319,13 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
346
319
if ( index > - 1 ) {
347
320
CdkDrag . _dragInstances . splice ( index , 1 ) ;
348
321
}
349
- this . _destroyed . next ( ) ;
350
- this . _destroyed . complete ( ) ;
351
- this . _dragRef . dispose ( ) ;
322
+
323
+ // Unnecessary in most cases, but used to avoid extra change detections with `zone-paths-rxjs`.
324
+ this . _ngZone . runOutsideAngular ( ( ) => {
325
+ this . _destroyed . next ( ) ;
326
+ this . _destroyed . complete ( ) ;
327
+ this . _dragRef . dispose ( ) ;
328
+ } ) ;
352
329
}
353
330
354
331
/** Syncs the root element with the `DragRef`. */
@@ -535,5 +512,40 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
535
512
}
536
513
}
537
514
515
+ /** Sets up the listener that syncs the handles with the drag ref. */
516
+ private _setupHandlesListener ( ) {
517
+ // Listen for any newly-added handles.
518
+ this . _handles . changes . pipe (
519
+ startWith ( this . _handles ) ,
520
+ // Sync the new handles with the DragRef.
521
+ tap ( ( handles : QueryList < CdkDragHandle > ) => {
522
+ const childHandleElements = handles
523
+ . filter ( handle => handle . _parentDrag === this )
524
+ . map ( handle => handle . element ) ;
525
+
526
+ // Usually handles are only allowed to be a descendant of the drag element, but if
527
+ // the consumer defined a different drag root, we should allow the drag element
528
+ // itself to be a handle too.
529
+ if ( this . _selfHandle && this . rootElementSelector ) {
530
+ childHandleElements . push ( this . element ) ;
531
+ }
532
+
533
+ this . _dragRef . withHandles ( childHandleElements ) ;
534
+ } ) ,
535
+ // Listen if the state of any of the handles changes.
536
+ switchMap ( ( handles : QueryList < CdkDragHandle > ) => {
537
+ return merge ( ...handles . map ( item => {
538
+ return item . _stateChanges . pipe ( startWith ( item ) ) ;
539
+ } ) ) as Observable < CdkDragHandle > ;
540
+ } ) ,
541
+ takeUntil ( this . _destroyed )
542
+ ) . subscribe ( handleInstance => {
543
+ // Enabled/disable the handle that changed in the DragRef.
544
+ const dragRef = this . _dragRef ;
545
+ const handle = handleInstance . element . nativeElement ;
546
+ handleInstance . disabled ? dragRef . disableHandle ( handle ) : dragRef . enableHandle ( handle ) ;
547
+ } ) ;
548
+ }
549
+
538
550
static ngAcceptInputType_disabled : BooleanInput ;
539
551
}
0 commit comments