Skip to content

Commit 047e3a6

Browse files
committed
fix(drag-drop): standalone draggable drag class not being applied with OnPush change detection
Fixes the styling that is applied while an item is dragged not being applied with `OnPush` change detection.
1 parent 73d0fb9 commit 047e3a6

File tree

3 files changed

+52
-8
lines changed

3 files changed

+52
-8
lines changed

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

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

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

2751+
@Component({
2752+
changeDetection: ChangeDetectionStrategy.OnPush,
2753+
template: `
2754+
<div cdkDrag #dragElement style="width: 100px; height: 100px; background: red;"></div>
2755+
`
2756+
})
2757+
class StandaloneDraggableWithOnPush {
2758+
@ViewChild('dragElement') dragElement: ElementRef<HTMLElement>;
2759+
@ViewChild(CdkDrag) dragInstance: CdkDrag;
2760+
}
2761+
27322762
@Component({
27332763
template: `
27342764
<svg><g

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

Lines changed: 21 additions & 7 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';
@@ -170,15 +171,17 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
170171
private _viewportRuler: ViewportRuler,
171172
private _dragDropRegistry: DragDropRegistry<DragRef, DropListRef>,
172173
@Inject(CDK_DRAG_CONFIG) private _config: DragRefConfig,
173-
@Optional() private _dir: Directionality) {
174+
@Optional() private _dir: Directionality,
175+
// @breaking-change 8.0.0 _changeDetectorRef parameter to be made required.
176+
private _changeDetectorRef?: ChangeDetectorRef) {
174177

175178
const ref = this._dragRef = new DragRef(element, this._document, this._ngZone,
176179
this._viewContainerRef, this._viewportRuler, this._dragDropRegistry,
177180
this._config, this.dropContainer ? this.dropContainer._dropListRef : undefined,
178181
this._dir);
179182
ref.data = this;
180183
this._syncInputs(ref);
181-
this._proxyEvents(ref);
184+
this._handleEvents(ref);
182185
}
183186

184187
/**
@@ -286,13 +289,17 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
286289
});
287290
}
288291

289-
/**
290-
* Proxies the events from a DragRef to events that
291-
* match the interfaces of the CdkDrag outputs.
292-
*/
293-
private _proxyEvents(ref: DragRef<CdkDrag<T>>) {
292+
/** Handles the events from the underlying `DragRef`. */
293+
private _handleEvents(ref: DragRef<CdkDrag<T>>) {
294294
ref.started.subscribe(() => {
295295
this.started.emit({source: this});
296+
297+
// Since all of these events run outside of change detection,
298+
// we need to ensure that everything is marked correctly.
299+
if (this._changeDetectorRef) {
300+
// @breaking-change 8.0.0 Remove null check for _changeDetectorRef
301+
this._changeDetectorRef.markForCheck();
302+
}
296303
});
297304

298305
ref.released.subscribe(() => {
@@ -301,6 +308,13 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
301308

302309
ref.ended.subscribe(() => {
303310
this.ended.emit({source: this});
311+
312+
// Since all of these events run outside of change detection,
313+
// we need to ensure that everything is marked correctly.
314+
if (this._changeDetectorRef) {
315+
// @breaking-change 8.0.0 Remove null check for _changeDetectorRef
316+
this._changeDetectorRef.markForCheck();
317+
}
304318
});
305319

306320
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
@@ -27,7 +27,7 @@ export declare class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDes
2727
started: EventEmitter<CdkDragStart>;
2828
constructor(
2929
element: ElementRef<HTMLElement>,
30-
dropContainer: CdkDropList, _document: any, _ngZone: NgZone, _viewContainerRef: ViewContainerRef, _viewportRuler: ViewportRuler, _dragDropRegistry: DragDropRegistry<DragRef, DropListRef>, _config: DragRefConfig, _dir: Directionality);
30+
dropContainer: CdkDropList, _document: any, _ngZone: NgZone, _viewContainerRef: ViewContainerRef, _viewportRuler: ViewportRuler, _dragDropRegistry: DragDropRegistry<DragRef, DropListRef>, _config: DragRefConfig, _dir: Directionality, _changeDetectorRef?: ChangeDetectorRef | undefined);
3131
getPlaceholderElement(): HTMLElement;
3232
getRootElement(): HTMLElement;
3333
ngAfterViewInit(): void;

0 commit comments

Comments
 (0)