Skip to content

Commit 41b74bd

Browse files
committed
refactor(cdk/drag-drop): track directives in registry
Switches to tracking the registered directive nodes in the registry instead of a private static field. This allows us to reuse the logic in the handles.
1 parent c04f84f commit 41b74bd

File tree

3 files changed

+46
-19
lines changed

3 files changed

+46
-19
lines changed

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

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ import type {CdkDropList} from './drop-list';
4848
import {DragDrop} from '../drag-drop';
4949
import {CDK_DRAG_CONFIG, DragDropConfig, DragStartDelay, DragAxis} from './config';
5050
import {assertElementNode} from './assertions';
51-
52-
const DRAG_HOST_CLASS = 'cdk-drag';
51+
import {DragDropRegistry} from '../drag-drop-registry';
5352

5453
/**
5554
* Injection token that can be used to reference instances of `CdkDropList`. It serves as
@@ -63,7 +62,7 @@ export const CDK_DROP_LIST = new InjectionToken<CdkDropList>('CdkDropList');
6362
selector: '[cdkDrag]',
6463
exportAs: 'cdkDrag',
6564
host: {
66-
'class': DRAG_HOST_CLASS,
65+
'class': 'cdk-drag',
6766
'[class.cdk-drag-disabled]': 'disabled',
6867
'[class.cdk-drag-dragging]': '_dragRef.isDragging()',
6968
},
@@ -78,9 +77,9 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
7877
private _changeDetectorRef = inject(ChangeDetectorRef);
7978
private _selfHandle = inject<CdkDragHandle>(CDK_DRAG_HANDLE, {optional: true, self: true});
8079
private _parentDrag = inject<CdkDrag>(CDK_DRAG_PARENT, {optional: true, skipSelf: true});
80+
private _dragDropRegistry = inject(DragDropRegistry);
8181

8282
private readonly _destroyed = new Subject<void>();
83-
private static _dragInstances: CdkDrag[] = [];
8483
private _handles = new BehaviorSubject<CdkDragHandle[]>([]);
8584
private _previewTemplate: CdkDragPreview | null;
8685
private _placeholderTemplate: CdkDragPlaceholder | null;
@@ -240,11 +239,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
240239
zIndex: config?.zIndex,
241240
});
242241
this._dragRef.data = this;
243-
244-
// We have to keep track of the drag instances in order to be able to match an element to
245-
// a drag instance. We can't go through the global registry of `DragRef`, because the root
246-
// element could be different.
247-
CdkDrag._dragInstances.push(this);
242+
this._dragDropRegistry.registerDirectiveNode(this.element.nativeElement, this);
248243

249244
if (config) {
250245
this._assignDefaults(config);
@@ -348,10 +343,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
348343
this.dropContainer.removeItem(this);
349344
}
350345

351-
const index = CdkDrag._dragInstances.indexOf(this);
352-
if (index > -1) {
353-
CdkDrag._dragInstances.splice(index, 1);
354-
}
346+
this._dragDropRegistry.removeDirectiveNode(this.element.nativeElement);
355347

356348
// Unnecessary in most cases, but used to avoid extra change detections with `zone-paths-rxjs`.
357349
this._ngZone.runOutsideAngular(() => {
@@ -487,12 +479,9 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
487479
// the item was projected into another item by something like `ngTemplateOutlet`.
488480
let parent = this.element.nativeElement.parentElement;
489481
while (parent) {
490-
if (parent.classList.contains(DRAG_HOST_CLASS)) {
491-
ref.withParent(
492-
CdkDrag._dragInstances.find(drag => {
493-
return drag.element.nativeElement === parent;
494-
})?._dragRef || null,
495-
);
482+
const parentDrag = this._dragDropRegistry.getDragDirectiveForNode(parent);
483+
if (parentDrag) {
484+
ref.withParent(parentDrag._dragRef);
496485
break;
497486
}
498487
parent = parent.parentElement;

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {_CdkPrivateStyleLoader} from '@angular/cdk/private';
2323
import {Observable, Observer, Subject, merge} from 'rxjs';
2424
import type {DropListRef} from './drop-list-ref';
2525
import type {DragRef} from './drag-ref';
26+
import type {CdkDrag} from './directives/drag';
2627

2728
/** Event options that can be used to bind an active, capturing event. */
2829
const activeCapturingEventOptions = normalizePassiveListenerOptions({
@@ -79,6 +80,13 @@ export class DragDropRegistry<_ = unknown, __ = unknown> implements OnDestroy {
7980
*/
8081
private _draggingPredicate = (item: DragRef) => item.isDragging();
8182

83+
/**
84+
* Map tracking DOM nodes and their corresponding drag directives. Note that this is different
85+
* from looking through the `_dragInstances` and getting their root node, because the root node
86+
* isn't necessarily the node that the directive is set on.
87+
*/
88+
private _domNodesToDirectives: WeakMap<Node, CdkDrag> | null = null;
89+
8290
/**
8391
* Emits the `touchmove` or `mousemove` events that are dispatched
8492
* while the user is dragging a drag item instance.
@@ -262,9 +270,36 @@ export class DragDropRegistry<_ = unknown, __ = unknown> implements OnDestroy {
262270
return merge(...streams);
263271
}
264272

273+
/**
274+
* Tracks the DOM node which has a draggable directive.
275+
* @param node Node to track.
276+
* @param dragRef Drag directive set on the node.
277+
*/
278+
registerDirectiveNode(node: Node, dragRef: CdkDrag): void {
279+
this._domNodesToDirectives ??= new WeakMap();
280+
this._domNodesToDirectives.set(node, dragRef);
281+
}
282+
283+
/**
284+
* Stops tracking a draggable directive node.
285+
* @param node Node to stop tracking.
286+
*/
287+
removeDirectiveNode(node: Node): void {
288+
this._domNodesToDirectives?.delete(node);
289+
}
290+
291+
/**
292+
* Gets the drag directive corresponding to a specific DOM node, if any.
293+
* @param node Node for which to do the lookup.
294+
*/
295+
getDragDirectiveForNode(node: Node): CdkDrag | null {
296+
return this._domNodesToDirectives?.get(node) || null;
297+
}
298+
265299
ngOnDestroy() {
266300
this._dragInstances.forEach(instance => this.removeDragItem(instance));
267301
this._dropInstances.forEach(instance => this.removeDropContainer(instance));
302+
this._domNodesToDirectives = null;
268303
this._clearGlobalListeners();
269304
this.pointerMove.complete();
270305
this.pointerUp.complete();

tools/public_api_guard/cdk/drag-drop.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,13 +351,16 @@ export class DragDropModule {
351351
// @public
352352
export class DragDropRegistry<_ = unknown, __ = unknown> implements OnDestroy {
353353
constructor(...args: unknown[]);
354+
getDragDirectiveForNode(node: Node): CdkDrag | null;
354355
isDragging(drag: DragRef): boolean;
355356
// (undocumented)
356357
ngOnDestroy(): void;
357358
readonly pointerMove: Subject<TouchEvent | MouseEvent>;
358359
readonly pointerUp: Subject<TouchEvent | MouseEvent>;
360+
registerDirectiveNode(node: Node, dragRef: CdkDrag): void;
359361
registerDragItem(drag: DragRef): void;
360362
registerDropContainer(drop: DropListRef): void;
363+
removeDirectiveNode(node: Node): void;
361364
removeDragItem(drag: DragRef): void;
362365
removeDropContainer(drop: DropListRef): void;
363366
// @deprecated

0 commit comments

Comments
 (0)