mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
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:
committed by
vivian-hu
parent
ecbcbf645e
commit
1d4bb18dab
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user