Skip to content

Commit d998227

Browse files
committed
feat(drag-drop): add function to determine whether an item is allowed to be transferred
Adds the `enterPredicate` function which allows consumers to determine whether a particular item is allowed to be moved into a drop container. This is more granular than excluding entire groups of items using `connectedTo`.
1 parent 7e74b5d commit d998227

File tree

4 files changed

+43
-8
lines changed

4 files changed

+43
-8
lines changed

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

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,34 @@ describe('CdkDrag', () => {
942942
});
943943
}));
944944

945+
it('should not be able to transfer an item that does not match the `enterPredicate`',
946+
fakeAsync(() => {
947+
const fixture = createComponent(ConnectedDropZones);
948+
949+
fixture.detectChanges();
950+
fixture.componentInstance.dropInstances.forEach(d => d.enterPredicate = () => false);
951+
fixture.detectChanges();
952+
953+
const groups = fixture.componentInstance.groupedDragItems.slice();
954+
const element = groups[0][1].element.nativeElement;
955+
const dropInstances = fixture.componentInstance.dropInstances.toArray();
956+
const targetRect = groups[1][2].element.nativeElement.getBoundingClientRect();
957+
958+
dragElementViaMouse(fixture, element, targetRect.left + 1, targetRect.top + 1);
959+
flush();
960+
fixture.detectChanges();
961+
962+
const event = fixture.componentInstance.droppedSpy.calls.mostRecent().args[0];
963+
964+
expect(event).toBeTruthy();
965+
expect(event).toEqual({
966+
previousIndex: 1,
967+
currentIndex: 1,
968+
item: groups[0][1],
969+
container: dropInstances[0],
970+
previousContainer: dropInstances[0]
971+
});
972+
}));
945973

946974
it('should be able to start dragging after an item has been transferred', fakeAsync(() => {
947975
const fixture = createComponent(ConnectedDropZones);
@@ -1129,7 +1157,7 @@ export class StandaloneDraggableWithMultipleHandles {
11291157
<div
11301158
*ngFor="let item of items"
11311159
cdkDrag
1132-
[data]="item"
1160+
[cdkDragData]="item"
11331161
style="width: 100%; height: ${ITEM_HEIGHT}px; background: red;">{{item}}</div>
11341162
</cdk-drop>
11351163
`
@@ -1239,15 +1267,15 @@ export class DraggableInDropZoneWithCustomPlaceholder {
12391267
[data]="todo"
12401268
[connectedTo]="[doneZone]"
12411269
(dropped)="droppedSpy($event)">
1242-
<div *ngFor="let item of todo" cdkDrag>{{item}}</div>
1270+
<div [cdkDragData]="item" *ngFor="let item of todo" cdkDrag>{{item}}</div>
12431271
</cdk-drop>
12441272
12451273
<cdk-drop
12461274
#doneZone
12471275
[data]="done"
12481276
[connectedTo]="[todoZone]"
12491277
(dropped)="droppedSpy($event)">
1250-
<div *ngFor="let item of done" cdkDrag>{{item}}</div>
1278+
<div [cdkDragData]="item" *ngFor="let item of done" cdkDrag>{{item}}</div>
12511279
</cdk-drop>
12521280
`
12531281
})

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export class CdkDrag<T = any> implements OnDestroy {
123123
@ContentChild(CdkDragPlaceholder) _placeholderTemplate: CdkDragPlaceholder;
124124

125125
/** Arbitrary data to attach to this drag instance. */
126-
@Input() data: T;
126+
@Input('cdkDragData') data: T;
127127

128128
/** Locks the position of the dragged element along the specified axis. */
129129
@Input('cdkDragLockAxis') lockAxis: 'x' | 'y';
@@ -364,7 +364,7 @@ export class CdkDrag<T = any> implements OnDestroy {
364364
*/
365365
private _updateActiveDropContainer({x, y}) {
366366
// Drop container that draggable has been moved into.
367-
const newContainer = this.dropContainer._getSiblingContainerFromPosition(x, y);
367+
const newContainer = this.dropContainer._getSiblingContainerFromPosition(this, x, y);
368368

369369
if (newContainer) {
370370
this._ngZone.run(() => {

src/cdk-experimental/drag-drop/drop-container.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export interface CdkDropContainer<T = any> {
5454
getItemIndex(item: CdkDrag): number;
5555
_sortItem(item: CdkDrag, xOffset: number, yOffset: number): void;
5656
_draggables: QueryList<CdkDrag>;
57-
_getSiblingContainerFromPosition(x: number, y: number): CdkDropContainer | null;
57+
_getSiblingContainerFromPosition(item: CdkDrag, x: number, y: number): CdkDropContainer | null;
5858
}
5959

6060
/**

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ export class CdkDrop<T = any> implements OnInit, OnDestroy {
7272
/** Locks the position of the draggable elements inside the container along the specified axis. */
7373
@Input() lockAxis: 'x' | 'y';
7474

75+
/**
76+
* Function that is used to determine whether an item
77+
* is allowed to be moved into a drop container.
78+
*/
79+
@Input() enterPredicate: (drag?: CdkDrag, drop?: CdkDrop) => boolean = () => true;
80+
7581
/** Emits when the user drops an item inside the container. */
7682
@Output() dropped: EventEmitter<CdkDragDrop<T, any>> = new EventEmitter<CdkDragDrop<T, any>>();
7783

@@ -252,16 +258,17 @@ export class CdkDrop<T = any> implements OnInit, OnDestroy {
252258
/**
253259
* Figures out whether an item should be moved into a sibling
254260
* drop container, based on its current position.
261+
* @param item Drag item that is being moved.
255262
* @param x Position of the item along the X axis.
256263
* @param y Position of the item along the Y axis.
257264
*/
258-
_getSiblingContainerFromPosition(x: number, y: number): CdkDrop | null {
265+
_getSiblingContainerFromPosition(item: CdkDrag, x: number, y: number): CdkDrop | null {
259266
const result = this._positionCache.siblings.find(({clientRect}) => {
260267
const {top, bottom, left, right} = clientRect;
261268
return y >= top && y <= bottom && x >= left && x <= right;
262269
});
263270

264-
return result ? result.drop : null;
271+
return result && result.drop.enterPredicate(item, this) ? result.drop : null;
265272
}
266273

267274
/** Refreshes the position cache of the items and sibling containers. */

0 commit comments

Comments
 (0)