Skip to content

Commit 3f89c36

Browse files
committed
refactor(drag-drop): add sorted event
Adds a new `cdkDropListSorted` event that emits the item's previous index and current index as it's being sorted in a list. Fixes #13863.
1 parent 30a8490 commit 3f89c36

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,15 @@ export interface CdkDragMove<T = any> {
7171
*/
7272
delta: {x: -1 | 0 | 1, y: -1 | 0 | 1};
7373
}
74+
75+
/** Event emitted when the user swaps the position of two drag items. */
76+
export interface CdkDragSort<T = any, I = T> {
77+
/** Index from which the item was sorted previously. */
78+
previousIndex: number;
79+
/** Index that the item is currently in. */
80+
currentIndex: number;
81+
/** Container that the item belongs to. */
82+
container: CdkDropListContainer<T>;
83+
/** Item that is being sorted. */
84+
item: CdkDrag<I>;
85+
}

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,36 @@ describe('CdkDrag', () => {
581581
.toEqual(['One', 'Two', 'Zero', 'Three']);
582582
}));
583583

584+
it('should dispatch the `sorted` event as an item is being sorted', fakeAsync(() => {
585+
const fixture = createComponent(DraggableInDropZone);
586+
fixture.detectChanges();
587+
588+
const items = fixture.componentInstance.dragItems.map(item => item.element.nativeElement);
589+
const draggedItem = items[0];
590+
const {top, left} = draggedItem.getBoundingClientRect();
591+
592+
startDraggingViaMouse(fixture, draggedItem, left, top);
593+
594+
// Drag over each item one-by-one going downwards.
595+
for (let i = 1; i < items.length; i++) {
596+
const elementRect = items[i].getBoundingClientRect();
597+
598+
dispatchMouseEvent(document, 'mousemove', elementRect.left, elementRect.top + 5);
599+
fixture.detectChanges();
600+
601+
expect(fixture.componentInstance.sortedSpy.calls.mostRecent().args[0]).toEqual({
602+
previousIndex: i - 1,
603+
currentIndex: i,
604+
item: fixture.componentInstance.dragItems.first,
605+
container: fixture.componentInstance.dropInstance
606+
});
607+
}
608+
609+
dispatchMouseEvent(document, 'mouseup');
610+
fixture.detectChanges();
611+
flush();
612+
}));
613+
584614
it('should not move items in a vertical list if the pointer is too far away', fakeAsync(() => {
585615
const fixture = createComponent(DraggableInDropZone);
586616
fixture.detectChanges();
@@ -1814,6 +1844,7 @@ class StandaloneDraggableWithMultipleHandles {
18141844
style="width: 100px; background: pink;"
18151845
[id]="dropZoneId"
18161846
[cdkDropListData]="items"
1847+
(cdkDropListSorted)="sortedSpy($event)"
18171848
(cdkDropListDropped)="droppedSpy($event)">
18181849
<div
18191850
*ngFor="let item of items"
@@ -1828,6 +1859,7 @@ class DraggableInDropZone {
18281859
@ViewChild(CdkDropList) dropInstance: CdkDropList;
18291860
items = ['Zero', 'One', 'Two', 'Three'];
18301861
dropZoneId = 'items';
1862+
sortedSpy = jasmine.createSpy('sorted spy');
18311863
droppedSpy = jasmine.createSpy('dropped spy').and.callFake((event: CdkDragDrop<string[]>) => {
18321864
moveItemInArray(this.items, event.previousIndex, event.currentIndex);
18331865
});

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
import {Directionality} from '@angular/cdk/bidi';
2424
import {CdkDrag} from './drag';
2525
import {DragDropRegistry} from './drag-drop-registry';
26-
import {CdkDragDrop, CdkDragEnter, CdkDragExit} from './drag-events';
26+
import {CdkDragDrop, CdkDragEnter, CdkDragExit, CdkDragSort} from './drag-events';
2727
import {moveItemInArray} from './drag-utils';
2828
import {CDK_DROP_LIST_CONTAINER} from './drop-list-container';
2929

@@ -101,6 +101,10 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
101101
@Output('cdkDropListExited')
102102
exited: EventEmitter<CdkDragExit<T>> = new EventEmitter<CdkDragExit<T>>();
103103

104+
/** Emits as the user is swapping items while dragging. */
105+
@Output('cdkDropListSorted')
106+
sorted: EventEmitter<CdkDragSort<T>> = new EventEmitter<CdkDragSort<T>>();
107+
104108
constructor(
105109
public element: ElementRef<HTMLElement>,
106110
private _dragDropRegistry: DragDropRegistry<CdkDrag, CdkDropList<T>>,
@@ -277,6 +281,13 @@ export class CdkDropList<T = any> implements OnInit, OnDestroy {
277281
// Shuffle the array in place.
278282
moveItemInArray(siblings, currentIndex, newIndex);
279283

284+
this.sorted.emit({
285+
previousIndex: currentIndex,
286+
currentIndex: newIndex,
287+
container: this,
288+
item
289+
});
290+
280291
siblings.forEach((sibling, index) => {
281292
// Don't do anything if the position hasn't changed.
282293
if (oldOrder[index] === sibling) {

0 commit comments

Comments
 (0)