0

With this Angular project, i'm trying to create elements that can be dragged to any location within the body. I want these changes to persist.

I tried to style the dragged element with position: relative, left: {the y value of the mouse's position, and top: {the x value of the mouses position}.

This works, but because you can drag an element from its middle, the dragged element jumps because the top left corner is being placed at the location of the mouse rather than the location on the element where the mouse is hovering.

So, I am trying to offset this by finding the distance from the top left corner of the element to the location of the mouse when dragging begins, and then using the difference to slightly alter the top, left styling.

dragx: Number;
dragy: Number;

dragstart(e){
    let x = e.pageX;
    let y = e.pageY;
    let drag = document.getElementById('drag');
    let rect = drag.getBoundingClientRect();
    let elX = rect.left;
    let elY = rect.top;
    this.dragx = elX - x;
    this.dragy = elY - Y;
    console.log("element position" + elX + ", " + elY);
    console.log("mouse position:" + x + ", " + y);
    console.log("difference" + this.dragx + ", " + this.dragy)
  }

In this bit of code, i'm just trying to assign a value to the global variables that represent the difference between the mouse and the element when first dragging. These will be used in the dragover function.

 dragover(e){
    let mousePosition = document.getElementById('mousePosition');
    let drag = document.getElementById('drag');
    let dragPosition = document.getElementById('elPosition');
    let x = e.pageX;
    let y = e.pageY;

    mousePosition.innerHTML = x + ", " + y;
    let rect = drag.getBoundingClientRect();
    dragPosition.innerHTML = rect.left.toString() + ", " + rect.top.toString(); 

    drag.style.position = "absolute";
    drag.style.top = y + "px";
    drag.style.left = x + "px";

    console.log("test" + this.dragy);

  }

The problem is that when I try to access these properties, like in the last line, i'm being told that dragy and dragx are undefined.

Maybe, I have a fundamental misunderstanding of global variables or properties or something. My question is why are dragx and dragy undefined?

Also, is this a good way to make draggable elements or am I overcomplicating it, or am I going about it the wrong way?

Thanks.

--- Edit --- Where the listeners get added.

  ngOnInit() {
    //console.log(document);
    this.dataService.getStyling().subscribe((stylings) => {
      this.stylings = stylings;
    });    
    this.el = document.getElementById('drag');
    let dragP = document.getElementById('elPosition');
    let rect = this.el.getBoundingClientRect();
    dragP.innerHTML = rect.left.toString() + ", " + rect.top.toString(); 
    this.el.addEventListener('dragstart', this.dragstart);
    this.el.addEventListener('ondrag', this.ondrag);
    document.addEventListener('dragover', this.dragover);
  }
  • Can you please add the code that shows how `dragover` and `dragstart` are being called / added as listeners? – user184994 Oct 08 '18 at 19:45
  • Just added it. Thanks for response. – Miles Moran Oct 08 '18 at 19:47
  • 2
    Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – ConnorsFan Oct 08 '18 at 19:49
  • After I linked it I noticed that the dragover listener applied to the document rather than the element, so I changed all the listeners to look for all events within the document. This fixed the issue, but i'm not sure why. Can you explain? – Miles Moran Oct 08 '18 at 19:50
  • It is because `this` is incorrect in the callback. Use `this.el.addEventListener('dragstart', (e) => this.dragstart(e));` or `this.el.addEventListener('dragstart', this.dragstart.bind(this));`. – ConnorsFan Oct 08 '18 at 19:53

1 Answers1

1

The reason is your context of this is being lost. You can use something like:

this.el.addEventListener('dragstart', this.dragstart.bind(this));

Or

this.el.addEventListener('dragstart', (e) => this.dragstart(e));

Bear in mind you will need to change all of the addEventListeners

user184994
  • 17,791
  • 1
  • 46
  • 52