fix(drag-drop): drop list not toggling dragging class inside component with OnPush change detection (#13703)

Fixes the `CdkDropList` not toggling its `cdk-drop-list-dragging` class if it's placed inside a component with `OnPush` change detection.

Fixes #13680.
This commit is contained in:
Kristiyan Kostadinov
2018-11-05 22:16:05 +01:00
committed by Jeremy Elbourn
parent d0d97c3e37
commit 12c15ba999
3 changed files with 50 additions and 20 deletions
+45 -17
View File
@@ -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<CdkDragHandle>;
}
@Component({
template: `
const DROP_ZONE_FIXTURE_TEMPLATE = `
<div
cdkDropList
style="width: 100px; background: pink;"
[id]="dropZoneId"
[cdkDropListData]="items"
(cdkDropListDropped)="droppedSpy($event)">
<div
cdkDropList
style="width: 100px; background: pink;"
[id]="dropZoneId"
[cdkDropListData]="items"
(cdkDropListDropped)="droppedSpy($event)">
<div
*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}}</div>
</div>
`
})
*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}}</div>
</div>
`;
@Component({template: DROP_ZONE_FIXTURE_TEMPLATE})
class DraggableInDropZone {
@ViewChildren(CdkDrag) dragItems: QueryList<CdkDrag>;
@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,
+2 -3
View File
@@ -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({
+3
View File
@@ -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<T = any> implements OnInit, OnDestroy {
constructor(
public element: ElementRef<HTMLElement>,
private _dragDropRegistry: DragDropRegistry<CdkDrag, CdkDropList<T>>,
private _changeDetectorRef: ChangeDetectorRef,
@Optional() private _dir?: Directionality) {}
ngOnInit() {
@@ -175,6 +177,7 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
this._dragging = true;
this._activeDraggables = this._draggables.toArray();
this._cachePositions();
this._changeDetectorRef.markForCheck();
}
/**