From e5863b5029df6197d96845453771ec08b61557f3 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sat, 20 Oct 2018 11:02:36 +0200 Subject: [PATCH] fix(drag-drop): drop list not toggling dragging class inside component with OnPush change detection Fixes the `CdkDropList` not toggling its `cdk-drop-list-dragging` class if it's placed inside a component with `OnPush` change detection. Fixes #13680. --- src/cdk/drag-drop/drag.spec.ts | 62 ++++++++++++++++++++++++---------- src/cdk/drag-drop/drag.ts | 5 ++- src/cdk/drag-drop/drop-list.ts | 3 ++ 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/cdk/drag-drop/drag.spec.ts b/src/cdk/drag-drop/drag.spec.ts index a927d090ecaa..b0c66f523b0d 100644 --- a/src/cdk/drag-drop/drag.spec.ts +++ b/src/cdk/drag-drop/drag.spec.ts @@ -9,6 +9,7 @@ import { ViewChild, ViewChildren, ViewEncapsulation, + ChangeDetectionStrategy, } from '@angular/core'; import {TestBed, ComponentFixture, fakeAsync, flush, tick} from '@angular/core/testing'; import {DragDropModule} from './drag-drop-module'; @@ -547,6 +548,27 @@ describe('CdkDrag', () => { expect(dropZone.element.nativeElement.classList).not.toContain('cdk-drop-dragging'); })); + it('should toggle a class when the user starts dragging an item with OnPush change detection', + fakeAsync(() => { + const fixture = createComponent(DraggableInOnPushDropZone); + fixture.detectChanges(); + const item = fixture.componentInstance.dragItems.toArray()[1].element.nativeElement; + const dropZone = fixture.componentInstance.dropInstance; + + expect(dropZone.element.nativeElement.classList).not.toContain('cdk-drop-list-dragging'); + + startDraggingViaMouse(fixture, item); + + expect(dropZone.element.nativeElement.classList).toContain('cdk-drop-list-dragging'); + + dispatchMouseEvent(document, 'mouseup'); + fixture.detectChanges(); + flush(); + fixture.detectChanges(); + + expect(dropZone.element.nativeElement.classList).not.toContain('cdk-drop-dragging'); + })); + it('should not toggle dragging class if the element was not dragged more than the threshold', fakeAsync(() => { const fixture = createComponent(DraggableInDropZone, [], 5); @@ -1991,24 +2013,24 @@ class StandaloneDraggableWithMultipleHandles { @ViewChildren(CdkDragHandle) handles: QueryList; } -@Component({ - template: ` +const DROP_ZONE_FIXTURE_TEMPLATE = ` +
-
{{item.value}}
-
- ` -}) + *ngFor="let item of items" + cdkDrag + [cdkDragData]="item" + [style.height.px]="item.height" + [style.margin-bottom.px]="item.margin" + style="width: 100%; background: red;">{{item.value}}
+ +`; + +@Component({template: DROP_ZONE_FIXTURE_TEMPLATE}) class DraggableInDropZone { @ViewChildren(CdkDrag) dragItems: QueryList; @ViewChild(CdkDropList) dropInstance: CdkDropList; @@ -2024,6 +2046,12 @@ class DraggableInDropZone { }); } +@Component({ + template: DROP_ZONE_FIXTURE_TEMPLATE, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +class DraggableInOnPushDropZone extends DraggableInDropZone {} + @Component({ encapsulation: ViewEncapsulation.None, diff --git a/src/cdk/drag-drop/drag.ts b/src/cdk/drag-drop/drag.ts index 5dc354f4b9dd..34942f83d2de 100644 --- a/src/cdk/drag-drop/drag.ts +++ b/src/cdk/drag-drop/drag.ts @@ -28,7 +28,7 @@ import { SkipSelf, ViewContainerRef, } from '@angular/core'; -import {supportsPassiveEventListeners} from '@angular/cdk/platform'; +import {normalizePassiveListenerOptions} from '@angular/cdk/platform'; import {Observable, Subject, Subscription, Observer} from 'rxjs'; import {take} from 'rxjs/operators'; import {DragDropRegistry} from './drag-drop-registry'; @@ -80,8 +80,7 @@ export function CDK_DRAG_CONFIG_FACTORY(): CdkDragConfig { } /** Options that can be used to bind a passive event listener. */ -const passiveEventListenerOptions = supportsPassiveEventListeners() ? - {passive: true} as EventListenerOptions : false; +const passiveEventListenerOptions = normalizePassiveListenerOptions({passive: true}); /** Element that can be moved inside a CdkDropList container. */ @Directive({ diff --git a/src/cdk/drag-drop/drop-list.ts b/src/cdk/drag-drop/drop-list.ts index 0d396499ac5f..f0ed6365baf0 100644 --- a/src/cdk/drag-drop/drop-list.ts +++ b/src/cdk/drag-drop/drop-list.ts @@ -19,6 +19,7 @@ import { QueryList, Optional, Directive, + ChangeDetectorRef, } from '@angular/core'; import {Directionality} from '@angular/cdk/bidi'; import {CdkDrag} from './drag'; @@ -141,6 +142,7 @@ export class CdkDropList implements OnInit, OnDestroy { constructor( public element: ElementRef, private _dragDropRegistry: DragDropRegistry>, + private _changeDetectorRef: ChangeDetectorRef, @Optional() private _dir?: Directionality) {} ngOnInit() { @@ -175,6 +177,7 @@ export class CdkDropList implements OnInit, OnDestroy { this._dragging = true; this._activeDraggables = this._draggables.toArray(); this._cachePositions(); + this._changeDetectorRef.markForCheck(); } /**