Skip to content

Commit 7199ee6

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 8aaca12 commit 7199ee6

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
@@ -851,6 +851,34 @@ describe('CdkDrag', () => {
851851
});
852852
}));
853853

854+
it('should not be able to transfer an item that does not match the `enterPredicate`',
855+
fakeAsync(() => {
856+
const fixture = createComponent(ConnectedDropZones);
857+
858+
fixture.detectChanges();
859+
fixture.componentInstance.dropInstances.forEach(d => d.enterPredicate = () => false);
860+
fixture.detectChanges();
861+
862+
const groups = fixture.componentInstance.groupedDragItems.slice();
863+
const element = groups[0][1].element.nativeElement;
864+
const dropInstances = fixture.componentInstance.dropInstances.toArray();
865+
const targetRect = groups[1][2].element.nativeElement.getBoundingClientRect();
866+
867+
dragElementViaMouse(fixture, element, targetRect.left + 1, targetRect.top + 1);
868+
flush();
869+
fixture.detectChanges();
870+
871+
const event = fixture.componentInstance.droppedSpy.calls.mostRecent().args[0];
872+
873+
expect(event).toBeTruthy();
874+
expect(event).toEqual({
875+
previousIndex: 1,
876+
currentIndex: 1,
877+
item: groups[0][1],
878+
container: dropInstances[0],
879+
previousContainer: dropInstances[0]
880+
});
881+
}));
854882

855883
it('should be able to start dragging after an item has been transferred', fakeAsync(() => {
856884
const fixture = createComponent(ConnectedDropZones);
@@ -1038,7 +1066,7 @@ export class StandaloneDraggableWithMultipleHandles {
10381066
<div
10391067
*ngFor="let item of items"
10401068
cdkDrag
1041-
[data]="item"
1069+
[cdkDragData]="item"
10421070
style="width: 100%; height: ${ITEM_HEIGHT}px; background: red;">{{item}}</div>
10431071
</cdk-drop>
10441072
`
@@ -1147,15 +1175,15 @@ export class DraggableInDropZoneWithCustomPlaceholder {
11471175
[data]="todo"
11481176
[connectedTo]="[doneZone]"
11491177
(dropped)="droppedSpy($event)">
1150-
<div *ngFor="let item of todo" cdkDrag>{{item}}</div>
1178+
<div [cdkDragData]="item" *ngFor="let item of todo" cdkDrag>{{item}}</div>
11511179
</cdk-drop>
11521180
11531181
<cdk-drop
11541182
#doneZone
11551183
[data]="done"
11561184
[connectedTo]="[todoZone]"
11571185
(dropped)="droppedSpy($event)">
1158-
<div *ngFor="let item of done" cdkDrag>{{item}}</div>
1186+
<div [cdkDragData]="item" *ngFor="let item of done" cdkDrag>{{item}}</div>
11591187
</cdk-drop>
11601188
`
11611189
})

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

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

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

130130
/** Emits when the user starts dragging the item. */
131131
@Output('cdkDragStarted') started: EventEmitter<CdkDragStart> = new EventEmitter<CdkDragStart>();
@@ -363,7 +363,7 @@ export class CdkDrag<T = any> implements OnDestroy {
363363
*/
364364
private _updateActiveDropContainer({x, y}: Point) {
365365
// Drop container that draggable has been moved into.
366-
const newContainer = this.dropContainer._getSiblingContainerFromPosition(x, y);
366+
const newContainer = this.dropContainer._getSiblingContainerFromPosition(this, x, y);
367367

368368
if (newContainer) {
369369
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
@@ -51,7 +51,7 @@ export interface CdkDropContainer<T = any> {
5151
getItemIndex(item: CdkDrag): number;
5252
_sortItem(item: CdkDrag, xOffset: number, yOffset: number): void;
5353
_draggables: QueryList<CdkDrag>;
54-
_getSiblingContainerFromPosition(x: number, y: number): CdkDropContainer | null;
54+
_getSiblingContainerFromPosition(item: CdkDrag, x: number, y: number): CdkDropContainer | null;
5555
}
5656

5757
/**

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ export class CdkDrop<T = any> implements OnInit, OnDestroy {
6969
*/
7070
@Input() id: string = `cdk-drop-${_uniqueIdCounter++}`;
7171

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

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

261-
return result ? result.drop : null;
268+
return result && result.drop.enterPredicate(item, this) ? result.drop : null;
262269
}
263270

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

0 commit comments

Comments
 (0)