Skip to content

Commit 2f63195

Browse files
crisbetojelbourn
authored andcommitted
fix(drag-drop): standalone draggable drag class not being applied with OnPush change detection (#14727)
Fixes the styling that is applied while an item is dragged not being applied with `OnPush` change detection.
1 parent c543cf6 commit 2f63195

File tree

3 files changed

+52
-9
lines changed

3 files changed

+52
-9
lines changed

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,25 @@ describe('CdkDrag', () => {
461461
expect(element.classList).not.toContain('cdk-drag-dragging');
462462
}));
463463

464+
it('should add a class while an element is being dragged with OnPush change detection',
465+
fakeAsync(() => {
466+
const fixture = createComponent(StandaloneDraggableWithOnPush);
467+
fixture.detectChanges();
468+
469+
const element = fixture.componentInstance.dragElement.nativeElement;
470+
471+
expect(element.classList).not.toContain('cdk-drag-dragging');
472+
473+
startDraggingViaMouse(fixture, element);
474+
475+
expect(element.classList).toContain('cdk-drag-dragging');
476+
477+
dispatchMouseEvent(document, 'mouseup');
478+
fixture.detectChanges();
479+
480+
expect(element.classList).not.toContain('cdk-drag-dragging');
481+
}));
482+
464483
it('should not add a class if item was not dragged more than the threshold', fakeAsync(() => {
465484
const fixture = createComponent(StandaloneDraggable, [], 5);
466485
fixture.detectChanges();
@@ -2830,6 +2849,17 @@ class StandaloneDraggable {
28302849
boundarySelector: string;
28312850
}
28322851

2852+
@Component({
2853+
changeDetection: ChangeDetectionStrategy.OnPush,
2854+
template: `
2855+
<div cdkDrag #dragElement style="width: 100px; height: 100px; background: red;"></div>
2856+
`
2857+
})
2858+
class StandaloneDraggableWithOnPush {
2859+
@ViewChild('dragElement') dragElement: ElementRef<HTMLElement>;
2860+
@ViewChild(CdkDrag) dragInstance: CdkDrag;
2861+
}
2862+
28332863
@Component({
28342864
template: `
28352865
<svg><g

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
ViewContainerRef,
2929
OnChanges,
3030
SimpleChanges,
31+
ChangeDetectorRef,
3132
} from '@angular/core';
3233
import {coerceBooleanProperty} from '@angular/cdk/coercion';
3334
import {Observable, Observer, Subject, merge} from 'rxjs';
@@ -175,11 +176,12 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
175176
@Optional() private _dir: Directionality,
176177

177178
/**
178-
* @deprecated `viewportRuler` and `dragDropRegistry` parameters
179+
* @deprecated `viewportRuler`, `dragDropRegistry` and `_changeDetectorRef` parameters
179180
* to be removed. Also `dragDrop` parameter to be made required.
180181
* @breaking-change 8.0.0.
181182
*/
182-
dragDrop?: DragDrop) {
183+
dragDrop?: DragDrop,
184+
private _changeDetectorRef?: ChangeDetectorRef) {
183185

184186

185187
// @breaking-change 8.0.0 Remove null check once the paramter is made required.
@@ -192,7 +194,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
192194

193195
this._dragRef.data = this;
194196
this._syncInputs(this._dragRef);
195-
this._proxyEvents(this._dragRef);
197+
this._handleEvents(this._dragRef);
196198
}
197199

198200
/**
@@ -313,13 +315,17 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
313315
});
314316
}
315317

316-
/**
317-
* Proxies the events from a DragRef to events that
318-
* match the interfaces of the CdkDrag outputs.
319-
*/
320-
private _proxyEvents(ref: DragRef<CdkDrag<T>>) {
318+
/** Handles the events from the underlying `DragRef`. */
319+
private _handleEvents(ref: DragRef<CdkDrag<T>>) {
321320
ref.started.subscribe(() => {
322321
this.started.emit({source: this});
322+
323+
// Since all of these events run outside of change detection,
324+
// we need to ensure that everything is marked correctly.
325+
if (this._changeDetectorRef) {
326+
// @breaking-change 8.0.0 Remove null check for _changeDetectorRef
327+
this._changeDetectorRef.markForCheck();
328+
}
323329
});
324330

325331
ref.released.subscribe(() => {
@@ -328,6 +334,13 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
328334

329335
ref.ended.subscribe(() => {
330336
this.ended.emit({source: this});
337+
338+
// Since all of these events run outside of change detection,
339+
// we need to ensure that everything is marked correctly.
340+
if (this._changeDetectorRef) {
341+
// @breaking-change 8.0.0 Remove null check for _changeDetectorRef
342+
this._changeDetectorRef.markForCheck();
343+
}
331344
});
332345

333346
ref.entered.subscribe(event => {

tools/public_api_guard/cdk/drag-drop.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export declare class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDes
2828
constructor(
2929
element: ElementRef<HTMLElement>,
3030
dropContainer: CdkDropList, _document: any, _ngZone: NgZone, _viewContainerRef: ViewContainerRef, viewportRuler: ViewportRuler, dragDropRegistry: DragDropRegistry<DragRef, DropListRef>, config: DragRefConfig, _dir: Directionality,
31-
dragDrop?: DragDrop);
31+
dragDrop?: DragDrop, _changeDetectorRef?: ChangeDetectorRef | undefined);
3232
getPlaceholderElement(): HTMLElement;
3333
getRootElement(): HTMLElement;
3434
ngAfterViewInit(): void;

0 commit comments

Comments
 (0)