Angular 2 allows for duplication of elements using drag and drop functionality

Check out my code on Plunker for drag and drop functionality in drag.ts: http://plnkr.co/edit/PITLKzBB6YXobR1gubOw?p=preview. Please note that it only works in a separate window preview.

import {Component, OnInit, ElementRef, Renderer} from '@angular/core'

@Component({
  selector: 'my-drag',
  template: `
    <div class="drag"
        draggable="true"
        (dragstart)="onDragStart($event)"
        (dragend)="onDragEnd($event)"
        (drag)="onDrag($event)">
      drag
    </div>
  `,
  styles: ['.drag {width: 50px; height: 50px; border: 1px solid black; background-color: red;}']
})
export class DragComponent implements OnInit {
  private dx: number = 0;
  private dy: number = 0;

  constructor(private el: ElementRef, private renderer: Renderer) { }

  ngOnInit() {
    this.renderer.setElementStyle(this.el.nativeElement, 'position', 'absolute');
  }

  onDragStart(event: MouseEvent) {
    this.dx = event.x - this.el.nativeElement.offsetLeft;
    this.dy = event.y - this.el.nativeElement.offsetTop;
  }

  onDrag(event: MouseEvent) {
    this.move(event.x, event.y);
    this.renderer.setElementAttribute(this.el.nativeElement, 'draggable', 'false');
  }

  onDragEnd(event: MouseEvent) {
    this.dx = 0;
    this.dy = 0;
  }

  move(x: number, y: number) {
    if (!x || !y) return;

    this.renderer.setElementStyle(this.el.nativeElement, 'top', (y - this.dy) + 'px');
    this.renderer.setElementStyle(this.el.nativeElement, 'left', (x - this.dx) + 'px');
  }
}

There are a couple of issues with the implementation:

  1. Duplicated div appears when dragged - how can this be fixed?
  2. Cursor changes during drag - how do I set it back to default?

Thank you for your help!

Answer №1

If you want to eliminate duplication, one approach is to set the native drag image to a transparent image.

  onDragStart(event: MouseEvent) {
    var dragImgEl = document.createElement('img'); 
    dragImgEl.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; // Using a small transparent image
    event.dataTransfer.setDragImage(dragImgEl, 0, 0);

    this.dx = event.x - this.el.nativeElement.offsetLeft;
    this.dy = event.y - this.el.nativeElement.offsetTop;
  }

Another way to achieve a similar effect is by manipulating opacity levels, although this may cause issues across different browsers.

If you wish to change the cursor appearance from the default circle, you can set the moveEffect on the element itself.

...
<div class="drag"
        draggable="true"
        (dragstart)="onDragStart($event)"
        (dragend)="onDragEnd($event)"
        (drag)="onDrag($event)"
        (dragover)="ondragover($event)">
      drag
    </div>
...

onDragStart(event: MouseEvent) {
    ..
    event.dataTransfer.effectAllowed = 'move';
    ...
}

ondragover(mouseEv: MouseEvent){
    mouseEv.dataTransfer.effectAllowed = 'move';
    mouseEv.preventDefault();
}

You can view a demo of this concept in action on Plunker: http://plnkr.co/edit/cGKcjxJGUKlWOC9GFyaJ?p=preview

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The date displayed in the table is incorrectly showing 04 instead of 03 when using the pipe

{{element.createdAt | date: 'MM/dd/yyyy h:mm'}} why are the dates in the database all showing as 23 but some values are displaying as 24? Please confirm. The first two values created in the db show a createdAt time of 3, but the table is showing ...

Problem with Jasmine in Angular 5 within Visual Studio Code

I am completely new to Angular 5 Unit testing and facing some challenges. Despite installing all @types/jasmine, I am encountering errors in my spec.ts file such as 'describle is not a name' and 'jasmine.createSpyObj does not exist on the ty ...

Building a custom Angular 6 pipe for generating a summary of a text snippet

Looking to create a pipe that limits the text box to only show the first 150 characters of the description. If the description is shorter than that, it should display the entire description followed by (...) Currently working on this: export class Tease ...

Creating global variables in NodeJS allows you to access and modify data

Currently, this construct is being utilized to create a global LOG: declare global { let LOG: Logger; } // eslint-disable-next-line @typescript-eslint/no-namespace declare namespace globalThis { let LOG: Logger; } globalThis.LOG = new Logger(); It f ...

Unable to submit data to PHP script using Angular 2

I am currently attempting to send a post request to a PHP script that contains the necessary data I require. Within home.component.ts: import { Component, OnInit } from '@angular/core'; import { UserComment } from '../definition/us ...

A guide on exporting the data type of a computed property in Vue3

I'm facing a challenge with my Vue3 component that interacts with GraphQL requests. After receiving a large JSON response, I utilize a computed property to extract the necessary value. Now, I aim to pass this extracted value as a prop to a child compo ...

Unusual output from the new Date() function: it displays the upcoming month

Your assistance and explanation are greatly appreciated. I have created a method that is supposed to return all the days of a given month by using two parameters- the year and the month: private _getDaysOfMonth(year: number, month: number): Array<Date& ...

Creating interactive carousel slides effortlessly with the power of Angular and the ngu-carousel module

I'm currently tackling the task of developing a carousel with the ngu-carousel Angular module, available at this link. However, I'm facing some challenges in configuring it to dynamically generate slides from an array of objects. From what I&apos ...

What is the best way to store the outcome of a promise in a variable within a TypeScript constructor?

Is it possible to store the result of a promise in a variable within the constructor using Typescript? I'm working with AdonisJS to retrieve data from the database, but the process involves using promises. How do I assign the result to a variable? T ...

Implementing Angular functionality with Bootstrap's collapse component

I am currently learning Angular and experimenting with two collapsible div elements. My goal is to have element-1 collapse and element-2 hide when button1 is clicked. Conversely, when button2 is clicked, I want element-2 to collapse and element-1 to hide. ...

Guide to utilizing Angular's translate i18n key as a dynamic parameter within HTML

Looking to pass an i18n translate service key as a parameter function on an HTML component. Attempted the following, but instead of getting the text, it's returning the key value. Created a variable assigned with the title in the component.ts file. ...

Configuring VS Code's "tasks.json" file to compile all .ts files can be done by following these steps

Apologies if this question has been asked before, but could someone please redirect me to the relevant thread if so. I am wondering if it is possible to set up VS Code's "tasks.json" to automatically compile all .ts files within a folder. Currently, I ...

Utilize the imported function from <Script> within NextJS

When working with vanilla JS, I am able to include a script like this: <head> <script src="https://api.site.com/js/v1/script.js"></script> </head> and then create an instance of it using: const fn = ScriptJS(); I can t ...

The specified type 'undefined' cannot be assigned to the type '"default" | "red" | "green" | "blue"

I am currently developing an app using React and TypeScript. Can someone help me troubleshoot and resolve the error message below? import { styled } from "linaria/react"; type Color = { color: "default" | "red" | "gree ...

Creating a component with @input for unit tests in Angular can be achieved through the following steps

I'm encountering issues while attempting to create a testing component with an @input. The component utilizes properties from the feedback model, and although I imported them into the test file, errors are being displayed. Can anyone offer assistance? ...

Issue with Angular 2 pipe causing unexpected undefined result

Here is a JSON format that I am working with: [{ "id": 9156, "slug": "chicken-seekh-wrap", "type": "dish", "title": "Chicken Seekh Wrap", "cuisine_type": [2140] }, { "id": 9150, "slug": "green-salad", "type": "dish", "title": "Green Sala ...

Using redux action in the onPaginationChange function instead of setPaginationState in the given example for the TanStack table - is there a way to

Provided this sample Is there a way to utilize by dispatching a redux action rather than using useState - setPaginationState? onPaginationChange: state => dispatch(browseItemModalActions.setPagination(state)) An error is appearing in the console: ...

An issue arising with the TypeScript antlr4ts listener type

I am currently attempting to incorporate the antlr4 parser into an angular project. Within a dataservice class, there is a function being called that appears as follows: parseRule() { const ruleString = ' STRING TO PARSE'; const inputS ...

Begin a hyperlink element with an onclick function that opens in a separate browser tab

I am having an issue with opening a link in a new tab. I have a button with an anchor tag inside that has a click event bound to it. Despite using target="_blank", the link still opens in the same tab. <button class="btn btn-primary"><a target ...

Utilize npm to compile TypeScript files as part of the npm build script execution

I am in the process of creating a build script using only npm, without relying on grunt or gulp. Most aspects are functioning well except for concatenating typescript files. While I can compile individual typescript files successfully, I am faced with th ...