Skip to content

Commit 6f5ca4d

Browse files
committed
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.
1 parent efeefd1 commit 6f5ca4d

File tree

3 files changed

+49
-19
lines changed

3 files changed

+49
-19
lines changed

src/cdk/drag-drop/drag.spec.ts

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
ViewChild,
1010
ViewChildren,
1111
ViewEncapsulation,
12+
ChangeDetectionStrategy,
1213
} from '@angular/core';
1314
import {TestBed, ComponentFixture, fakeAsync, flush, tick} from '@angular/core/testing';
1415
import {DragDropModule} from './drag-drop-module';
@@ -533,6 +534,27 @@ describe('CdkDrag', () => {
533534
expect(dropZone.element.nativeElement.classList).not.toContain('cdk-drop-dragging');
534535
}));
535536

537+
it('should toggle a class when the user starts dragging an item with OnPush change detection',
538+
fakeAsync(() => {
539+
const fixture = createComponent(DraggableInOnPushDropZone);
540+
fixture.detectChanges();
541+
const item = fixture.componentInstance.dragItems.toArray()[1].element.nativeElement;
542+
const dropZone = fixture.componentInstance.dropInstance;
543+
544+
expect(dropZone.element.nativeElement.classList).not.toContain('cdk-drop-list-dragging');
545+
546+
startDraggingViaMouse(fixture, item);
547+
548+
expect(dropZone.element.nativeElement.classList).toContain('cdk-drop-list-dragging');
549+
550+
dispatchMouseEvent(document, 'mouseup');
551+
fixture.detectChanges();
552+
flush();
553+
fixture.detectChanges();
554+
555+
expect(dropZone.element.nativeElement.classList).not.toContain('cdk-drop-dragging');
556+
}));
557+
536558
it('should not toggle dragging class if the element was not dragged more than the threshold',
537559
fakeAsync(() => {
538560
const fixture = createComponent(DraggableInDropZone, [], 5);
@@ -1807,22 +1829,22 @@ class StandaloneDraggableWithMultipleHandles {
18071829
@ViewChildren(CdkDragHandle) handles: QueryList<CdkDragHandle>;
18081830
}
18091831

1810-
@Component({
1811-
template: `
1812-
<div
1813-
cdkDropList
1814-
style="width: 100px; background: pink;"
1815-
[id]="dropZoneId"
1816-
[cdkDropListData]="items"
1817-
(cdkDropListDropped)="droppedSpy($event)">
1818-
<div
1819-
*ngFor="let item of items"
1820-
cdkDrag
1821-
[cdkDragData]="item"
1822-
style="width: 100%; height: ${ITEM_HEIGHT}px; background: red;">{{item}}</div>
1823-
</div>
1824-
`
1825-
})
1832+
const DROP_ZONE_FIXTURE_TEMPLATE = `
1833+
<div
1834+
cdkDropList
1835+
style="width: 100px; background: pink;"
1836+
[id]="dropZoneId"
1837+
[cdkDropListData]="items"
1838+
(cdkDropListDropped)="droppedSpy($event)">
1839+
<div
1840+
*ngFor="let item of items"
1841+
cdkDrag
1842+
[cdkDragData]="item"
1843+
style="width: 100%; height: ${ITEM_HEIGHT}px; background: red;">{{item}}</div>
1844+
</div>
1845+
`;
1846+
1847+
@Component({template: DROP_ZONE_FIXTURE_TEMPLATE})
18261848
class DraggableInDropZone {
18271849
@ViewChildren(CdkDrag) dragItems: QueryList<CdkDrag>;
18281850
@ViewChild(CdkDropList) dropInstance: CdkDropList;
@@ -1833,6 +1855,12 @@ class DraggableInDropZone {
18331855
});
18341856
}
18351857

1858+
@Component({
1859+
template: DROP_ZONE_FIXTURE_TEMPLATE,
1860+
changeDetection: ChangeDetectionStrategy.OnPush,
1861+
})
1862+
class DraggableInOnPushDropZone extends DraggableInDropZone {}
1863+
18361864

18371865
@Component({
18381866
encapsulation: ViewEncapsulation.None,

src/cdk/drag-drop/drag.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
SkipSelf,
2929
ViewContainerRef,
3030
} from '@angular/core';
31-
import {supportsPassiveEventListeners} from '@angular/cdk/platform';
31+
import {normalizePassiveListenerOptions} from '@angular/cdk/platform';
3232
import {Observable, Subject, Subscription, Observer} from 'rxjs';
3333
import {take} from 'rxjs/operators';
3434
import {DragDropRegistry} from './drag-drop-registry';
@@ -80,8 +80,7 @@ export function CDK_DRAG_CONFIG_FACTORY(): CdkDragConfig {
8080
}
8181

8282
/** Options that can be used to bind a passive event listener. */
83-
const passiveEventListenerOptions = supportsPassiveEventListeners() ?
84-
{passive: true} as EventListenerOptions : false;
83+
const passiveEventListenerOptions = normalizePassiveListenerOptions({passive: true});
8584

8685
/** Element that can be moved inside a CdkDropList container. */
8786
@Directive({

src/cdk/drag-drop/drop-list.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
QueryList,
2020
Optional,
2121
Directive,
22+
ChangeDetectorRef,
2223
} from '@angular/core';
2324
import {Directionality} from '@angular/cdk/bidi';
2425
import {CdkDrag} from './drag';
@@ -104,6 +105,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
104105
constructor(
105106
public element: ElementRef<HTMLElement>,
106107
private _dragDropRegistry: DragDropRegistry<CdkDrag, CdkDropList<T>>,
108+
private _changeDetectorRef: ChangeDetectorRef,
107109
@Optional() private _dir?: Directionality) {}
108110

109111
ngOnInit() {
@@ -142,6 +144,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
142144
this._dragging = true;
143145
this._activeDraggables = this._draggables.toArray();
144146
this._cachePositions();
147+
this._changeDetectorRef.markForCheck();
145148
}
146149

147150
/**

0 commit comments

Comments
 (0)