mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(drag-drop): error if drag item is destroyed zone has stabilized (#13978)
We initialize the `rootElement` in an `NgZone.onStable` callback, however if the zone doesn't stabilize before the `cdkDrag` is destroyed, we'll throw an error because there is no `rootElement`. These changes add an extra check to ensure that we don't throw.
This commit is contained in:
committed by
vivian-hu
parent
6c0fd37a29
commit
6fe84f317e
@@ -427,6 +427,14 @@ describe('CdkDrag', () => {
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should not throw if destroyed before the first change detection run', fakeAsync(() => {
|
||||
const fixture = createComponent(StandaloneDraggable);
|
||||
|
||||
expect(() => {
|
||||
fixture.destroy();
|
||||
}).not.toThrow();
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('draggable with a handle', () => {
|
||||
|
||||
+27
-18
@@ -175,6 +175,9 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
/** Subscription to the event that is dispatched when the user lifts their pointer. */
|
||||
private _pointerUpSubscription = Subscription.EMPTY;
|
||||
|
||||
/** Subscription to the stream that initializes the root element. */
|
||||
private _rootElementInitSubscription = Subscription.EMPTY;
|
||||
|
||||
/** Elements that can be used to drag the draggable item. */
|
||||
@ContentChildren(CdkDragHandle, {descendants: true}) _handles: QueryList<CdkDragHandle>;
|
||||
|
||||
@@ -265,30 +268,36 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
// element to be in the proper place in the DOM. This is mostly relevant
|
||||
// for draggable elements inside portals since they get stamped out in
|
||||
// their original DOM position and then they get transferred to the portal.
|
||||
this._ngZone.onStable.asObservable().pipe(take(1)).subscribe(() => {
|
||||
const rootElement = this._rootElement = this._getRootElement();
|
||||
rootElement.addEventListener('mousedown', this._pointerDown, passiveEventListenerOptions);
|
||||
rootElement.addEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
|
||||
toggleNativeDragInteractions(rootElement , false);
|
||||
});
|
||||
this._rootElementInitSubscription = this._ngZone.onStable.asObservable()
|
||||
.pipe(take(1))
|
||||
.subscribe(() => {
|
||||
const rootElement = this._rootElement = this._getRootElement();
|
||||
rootElement.addEventListener('mousedown', this._pointerDown, passiveEventListenerOptions);
|
||||
rootElement.addEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
|
||||
toggleNativeDragInteractions(rootElement , false);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this._rootElement.removeEventListener('mousedown', this._pointerDown,
|
||||
passiveEventListenerOptions);
|
||||
this._rootElement.removeEventListener('touchstart', this._pointerDown,
|
||||
passiveEventListenerOptions);
|
||||
this._destroyPreview();
|
||||
this._destroyPlaceholder();
|
||||
// The directive might have been destroyed before the root element is initialized.
|
||||
if (this._rootElement) {
|
||||
this._rootElement.removeEventListener('mousedown', this._pointerDown,
|
||||
passiveEventListenerOptions);
|
||||
this._rootElement.removeEventListener('touchstart', this._pointerDown,
|
||||
passiveEventListenerOptions);
|
||||
|
||||
// Do this check before removing from the registry since it'll
|
||||
// stop being considered as dragged once it is removed.
|
||||
if (this._isDragging()) {
|
||||
// Since we move out the element to the end of the body while it's being
|
||||
// dragged, we have to make sure that it's removed if it gets destroyed.
|
||||
this._removeElement(this._rootElement);
|
||||
// Do this check before removing from the registry since it'll
|
||||
// stop being considered as dragged once it is removed.
|
||||
if (this._isDragging()) {
|
||||
// Since we move out the element to the end of the body while it's being
|
||||
// dragged, we have to make sure that it's removed if it gets destroyed.
|
||||
this._removeElement(this._rootElement);
|
||||
}
|
||||
}
|
||||
|
||||
this._rootElementInitSubscription.unsubscribe();
|
||||
this._destroyPreview();
|
||||
this._destroyPlaceholder();
|
||||
this._nextSibling = null;
|
||||
this._dragDropRegistry.removeDragItem(this);
|
||||
this._removeSubscriptions();
|
||||
|
||||
Reference in New Issue
Block a user