Reset transform offset in Angular Material Drag and Drop
Asked Answered
U

3

10

I have a <div> element with position: absolute inside a container with position: relative. Its left and top properties are bound to data X and Y in the component.ts. My purpose is to move the div inside my container using cdk drag and drop.

On the dragEnded event I retrive the data I need to update the coordinates X and Y and so begins the problem...

<div
  class="character"
  [style.left.px]="x"
  [style.top.px]="y"
  cdkDrag
  cdkDragBoundary=".grid-container"
  (cdkDragEnded)="dragEnded($event, c)"
></div>

I notice that cdk drag and drop apply a property transform: translate3d(x,y,z) in order to move my div, starting from its original position. So, if I want my div left and top to be bound to my backend properties I can just calculate new coordinates on dragEnd event, apply them, and reset the transform property made by cdk. Everything works.

But the next time I drag the element, material don't apply the transform starting from the new absolute position of my div, but from the original one.

I thought one solution could be to check if the CdkDragEnd event contains the data relative to the transform starting point and reset it, but I didn't find anything.

Any idea if this proprty is hidden somewhere in the CdkDragEvent? Or have any other solution to this problem?

Urbanist answered 11/4, 2020 at 13:29 Comment(0)
B
13

In method that takes CdkDragEnd event you can reset transform property with event.source._dragRef.reset();. Example:

public dragEnded(event: CdkDragEnd): void {
    if (this.dragEnd.type === "cell" && this.dragStart.type !== "cell") {
      this.moveFromList1To2(event.source.element.nativeElement.id);
      event.source._dragRef.reset();
    }
  }
Bridgettebridgewater answered 21/11, 2020 at 22:40 Comment(1)
Thanks, "event.source._dragRef.reset();" this code is working fineEsra
S
4

Even if the version of @bakunet is working, this is considering bad practice to access private method and may not work, depend on your compiler.

Here on the official angular website, you can find the following solution.

Use of the ckdDragFreeDragPosition

<p>
  <button (click)="resetPosition()">reset position</button>
</p>

<div class="character" cdkDrag [cdkDragFreeDragPosition]="dragPosition">
  Drag me around
</div>
import {Component} from '@angular/core';

/**
 * @title Programmatically setting the free drag position
 */
@Component({
  selector: 'cdk-drag-drop-free-drag-position-example',
  templateUrl: 'cdk-drag-drop-free-drag-position-example.html',
  styleUrls: ['cdk-drag-drop-free-drag-position-example.css'],
})
export class CdkDragDropFreeDragPositionExample {
  dragPosition = {x: 0, y: 0};

  resetPosition() {
    this.dragPosition = {x: 0, y: 0};
  }
}

ckdDragFreeDragPosition use :

By default, standalone cdkDrag elements move from their normal DOM position only when manually moved by a user. The element's position can be explicitly set, however, via the cdkDragFreeDragPosition input. Applications commonly use this, for example, to restore a draggable's position after a user has navigated away and then returned.

Sturdivant answered 16/6, 2022 at 7:56 Comment(1)
It is also possible to use dragEvent.source.setFreeDragPosition({ x: 0, y: 0 });Elfont
R
1

I too faced this issue a while back. After a lot of time surfing on the internet for a way to reset the transform property, I got nothing.

Seems you cannot reset the transform property. What ever you do, the final position of the drag-div will be calculated by summing up the latest top, left, and transform properties.

My solution was not to change the left and top properties of the element dynamically and keep track of the x and y values by the (cdkDragEnded) event emitter

What I did is was,

  1. Create two fields xInitial = x and yInitial = y to store the initial co-ordinates of the div to drag
  2. Render you div initially with these initial co-ordninates;

    <div
        class="character"
        [style.left.px]="xInitial"
        [style.top.px]="yInitial"
        cdkDrag
        cdkDragBoundary=".grid-container"
        (cdkDragEnded)="dragEnded($event, c)"
    ></div>
    
  3. Modify dragEnded($event, c) to keep track of the actual position of the dragged div

    dragEnded(event, c) {
         let element = event.source.getRootElement();
         let newPos = element.getBoundingClientRect();
    
         this.x = newPos.x;
         this.y = newPos.y;
    }
    
  4. Finally save the values of this.x and this.y for initialising the component the next time.
Retrospection answered 30/4, 2020 at 10:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.