fix(drag-drop): dragging styling not being reset in some cases with OnPush change detection (#14725)

Fixes the `cdk-drop-list-dragging` and `cdk-drop-list-receiving` not being removed in some cases when using `OnPush` change detection. This seems to have been working until now, because there's always something else to trigger change detection, however if there isn't (e.g. the user isn't listening to the `dropped` event) they won't be reset.
This commit is contained in:
Kristiyan Kostadinov
2019-01-15 23:23:38 +01:00
committed by vivian-hu
parent ecbcbf645e
commit 1d4bb18dab
2 changed files with 52 additions and 6 deletions
+45
View File
@@ -844,6 +844,30 @@ describe('CdkDrag', () => {
expect(dropZone.element.nativeElement.classList).not.toContain('cdk-drop-dragging');
}));
it('should toggle the drop dragging classes if there is nothing to trigger change detection',
fakeAsync(() => {
const fixture = createComponent(DraggableInDropZoneWithoutEvents);
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');
expect(item.classList).not.toContain('cdk-drag-dragging');
startDraggingViaMouse(fixture, item);
expect(dropZone.element.nativeElement.classList).toContain('cdk-drop-list-dragging');
expect(item.classList).toContain('cdk-drag-dragging');
dispatchMouseEvent(document, 'mouseup');
fixture.detectChanges();
flush();
fixture.detectChanges();
expect(dropZone.element.nativeElement.classList).not.toContain('cdk-drop-dragging');
expect(item.classList).not.toContain('cdk-drag-dragging');
}));
it('should toggle a class when the user starts dragging an item with OnPush change detection',
fakeAsync(() => {
const fixture = createComponent(DraggableInOnPushDropZone);
@@ -3115,6 +3139,27 @@ class NestedDropListGroups {
class DraggableOnNgContainer {}
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div cdkDropList style="width: 100px; background: pink;">
<div *ngFor="let item of items"
cdkDrag
[style.height.px]="item.height"
style="width: 100%; background: red;">{{item.value}}</div>
</div>
`
})
class DraggableInDropZoneWithoutEvents {
@ViewChildren(CdkDrag) dragItems: QueryList<CdkDrag>;
@ViewChild(CdkDropList) dropInstance: CdkDropList;
items = [
{value: 'Zero', height: ITEM_HEIGHT},
{value: 'One', height: ITEM_HEIGHT},
{value: 'Two', height: ITEM_HEIGHT},
{value: 'Three', height: ITEM_HEIGHT}
];
}
/**
* Component that passes through whatever content is projected into it.
+7 -6
View File
@@ -151,7 +151,7 @@ export class CdkDropList<T = any> implements CdkDropListContainer, OnDestroy {
return this.enterPredicate(drag.data, drop.data);
};
this._syncInputs(ref);
this._proxyEvents(ref);
this._handleEvents(ref);
CdkDropList._dropLists.push(this);
if (_group) {
@@ -275,11 +275,8 @@ export class CdkDropList<T = any> implements CdkDropListContainer, OnDestroy {
});
}
/**
* Proxies the events from a DropListRef to events that
* match the interfaces of the CdkDropList outputs.
*/
private _proxyEvents(ref: DropListRef<CdkDropList>) {
/** Handles events from the underlying DropListRef. */
private _handleEvents(ref: DropListRef<CdkDropList>) {
ref.beforeStarted.subscribe(() => {
this._changeDetectorRef.markForCheck();
});
@@ -316,6 +313,10 @@ export class CdkDropList<T = any> implements CdkDropListContainer, OnDestroy {
item: event.item.data,
isPointerOverContainer: event.isPointerOverContainer
});
// Mark for check since all of these events run outside of change
// detection and we're not guaranteed for something else to have triggered it.
this._changeDetectorRef.markForCheck();
});
}