Cancel drag on key press Angular cdk Drag and Drop
Asked Answered
S

5

13

I´m working in a application implementing the new drag and drop from angular material CDK and i´m trying to cancel the drag event of the element pressing Esc, i mean, i start dragging the element but if i press Esc while i´m dragging the element, it should go back to the position from where i start dragging it, so far i haven´t found a way to do this, does anyone know how can i do this. There nothing in the cdk documentation about this any idea. i try doing something like this.

Template

<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
  <div class="example-box" *ngFor="let movie of movies" (cdkDragEnded)="onDragEnded($event)" cdkDrag>{{movie}}</div>
</div>

Ts component

onDragEnded(event: CdkDragEnd) {
  console.log(event)
  event.source.element.nativeElement.style.transform = 'none';
  const source: any = event.source;
  source._passiveTransform = { x: 0, y: 0 };
}

but no success so far.

Syne answered 4/12, 2018 at 9:5 Comment(3)
Have you solved it? Thank, E.Satirize
unfortunately not yet....Syne
To reset dragged element to its origin, instead of manually setting element transform and source._passiveTransform you can now do event.source._dragRef.reset();Keener
S
10

I also faced this problem for a long time. Finally I could fix it by dispatching a mouseup event that will act as the user releasing the mouse.

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
    if (event.key === 'Escape') {
        document.dispatchEvent(new Event('mouseup'));
    }
}

This is an extremely hacky solution and comes with it's down sides. In fact, you are not cancelling the drag but instead dropping. Meaning that if you are hovering a cdkDropList or one is active it will trigger the cdkDropListDropped emmiter for that list. Something you can easily workaround by adding a flag.

private _canceledByEsq = false;

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
    if (event.key === 'Escape') {
        this._canceledByEsq = true;
        document.dispatchEvent(new Event('mouseup'));
    }
}

handleDrop() {
    if (!this._canceledByEsq) {
        // Do my data manipulations
    }
}

Hope this helps you... :)

Sienna answered 24/1, 2019 at 18:44 Comment(0)
I
2

You can move the dragged item to a position using:

event['source']['element']['nativeElement']['style']['transform'] = 'translate3d(0,0,0)';
event['source']['_dragRef']['_activeTransform'] = {x: 0, y: 0};
event['source']['_dragRef']['_passiveTransform'] = {x: 0, y: 0};
Irina answered 17/1, 2019 at 11:45 Comment(0)
L
1

The best way to do it is to call event.source._dragRef.reset(); (as @AleRubis mentioned in comment) on ESC key press. Now the question is from where you can get that _dragRef outside cdkDrag events (ESC key event), you can save it in a component variable like this when drag starts.

Component:

cdkDragStarted = (event) => { this.dragRef = event.source._dragRef; }

Template:

<p cdkDrag (cdkDragStarted)="cdkDragStarted($event)"> Draggable paragraph </p>

Lagasse answered 6/11, 2019 at 11:31 Comment(1)
Didn't work for me. The dragRef.reset() seems to do nothing (tested with Angular 9.1.X). Thus, I prefer @danizep's solution.Floro
C
1

Here's a version using rxjs. It requires a reference to CdkDrag as ViewChild. Unfortunately, because there is no public method to stop dragging on the DragRef you have to use dispatchEvent as the only way to end the dragging process.

There are two parts in the example below. What's happening is that the ended event can only be listened to after a start, and that instance of listening can be stopped by a subject triggered by pressing escape.

  • In the AfterViewInit a subscription is created to the started EventEmitter from the CdkDrag directive.
  • After the start event, the stream that switches to listening to ended.
  • If the cancel request is fired, the stream will be ended by the takeUntil operator, and reset() will be called on the directive to reset the position and dispatchEvent() will be used to stop the drag process.
  • Otherwise once the end event is fired, the onDragEnded() method is called from the OP.
  • Unless there is some really funniness going on, the ended event will only be fired at most once per start, so there is no need for an additional take(1).
private dragCancelRequest = new Subject();

ngAfterViewInit() {
  this.drag.started.pipe(
    switchMap(({ source }) => source.ended.pipe(
      takeUntil(this.dragCancelRequest.pipe(tap(() => {
        source.reset();
        document.dispatchEvent(new Event('mouseup'));
      })))
    )),
    tap(x => this.onDragEnded(x))
  ).subscribe();
}

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
  if (event.key === 'Escape') {
    this.dragCancelRequest.next();
  }
}
Cusack answered 23/6, 2020 at 15:6 Comment(0)
S
-2

You can use something like...

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
    if (event.code === 'Escape') {
        // call dragend event
    }
}
Snapper answered 4/12, 2018 at 9:16 Comment(7)
Ok there i can check for key pressed, but how do i reset the element dragged to the original position and cancel the drag.Syne
you can remember x and y position in variable at drag start eventSnapper
that is not to specific, and the question is how to cancel the drag event after the drag start and is trigger for the mouse on keypress.Syne
at the time of dragging such element with any event you can get its actual position and use this position at time of cancel.. its helpful if you create stackbiz of your issue.Snapper
Ok the question is how to cancel the drag event not how to return the dragged element to the original position, only canceling the drag event the element return the original position without remembering x or y position, so the question is how to cancel the drag of the element ones the drag start.Syne
event.preventDefault(); // for stop drag event // fire mousevent continue const mouseMoveEvent = document.createEvent('MouseEvent'); mouseMoveEvent.initMouseEvent('mousemove', true,true, window); document.dispatchEvent(mouseMoveEvent); Snapper
Here you have a link where you can show me in the code how to do it because so far in that code you are only canceling the mouse event the drag event still working: [Drag&drop]stackblitz.com/edit/angular-deufx5Syne

© 2022 - 2024 — McMap. All rights reserved.