Is there a way to eliminate the transform style from a draggable element?

I am looking to enhance the CDK drag and drop example by adding a preview of the dragged element with specific left and top positions, without utilizing the transform style.

HTML

<div class="example-boundary">
  <div class="example-box" cdkDragBoundary=".example-boundary" cdkDrag>
    I can only be dragged within the dotted container
  </div>
</div>

<button> Preview the dragged element </buttona>

TypeScript

import {Component} from '@angular/core';
import {CdkDrag} from '@angular/cdk/drag-drop';

/**
 * @title Drag&Drop boundary
 */
@Component({
  selector: 'cdk-drag-drop-boundary-example',
  templateUrl: 'cdk-drag-drop-boundary-example.html',
  styleUrls: ['cdk-drag-drop-boundary-example.css'],
  standalone: true,
  imports: [CdkDrag],
})
export class CdkDragDropBoundaryExample {}

Current state

During dragging, the element renders like this in the DOM

<div _ngcontent-ng-c2320506461="" class="example-boundary">
  <div _ngcontent-ng-c2320506461="" cdkdragboundary=".example-boundary" cdkdrag="" class="cdk-drag example-box" style="transform: translate3d(202px, -2px, 0px);">
I can only be dragged within the dotted container
 </div>
</div>

Expected result

Once the element is dragged and the preview button is clicked, it should display as follows.

<div class="example-boundary">
  <div class="example-box" style="left: 96.13%; top: 9.92%; display: block;">
   Now I can't be dragged, sorry
  </div>
</div>

This means that the transform style will be replaced by left and top positions for the preview element.

Answer №1

@angular/cdk/drag-drop utilizes the transform property internally to position the box. The usage of top, left, and position properties or the transform property is encapsulated within the package and can be achieved in both ways. If you have specific requirements for manipulating the top and left properties, you can either calculate them from the original element position and transform, or implement a drag function in pure JS.

Here is a version using pure JavaScript to achieve the desired functionality:

const box = document.querySelector('.example-box');
const boundary = document.querySelector(box.getAttribute('cdkDragBoundary') || '');
const posDisplay = document.querySelector('#pos');

const offset = {
  x: 0,
  y: 0
};

const onMouseMove = (e) => {
  e.preventDefault();
  const [cx, cy] = [e.clientX, e.clientY];
  const {
    width,
    height
  } = box.getBoundingClientRect();
  let top = cy - offset.y;
  let left = cx - offset.x;

  const {
    width: bw,
    height: bh
  } = boundary?.getBoundingClientRect();
  top = Math.min(top, (bh || innerHeight) - height);
  top = Math.max(top, 0);
  left = Math.min(left, (bw || innerWidth) - width);
  left = Math.max(left, 0);
  box.style.top = top + 'px';
  box.style.left = left + 'px';
  posDisplay.innerText = `left: ${left}px, top: ${top}px`;
};

box.onmousedown = e => {
  e.preventDefault();
  offset.x = e.clientX - box.offsetLeft;
  offset.y = e.clientY - box.offsetTop;
  window.onmousemove = onMouseMove;
  window.onmouseup = () => {
    window.onmousemove = null;
    window.onmouseup = null;
  };
}
.example-boundary {
  position: relative;
  border: 1px dotted gray;
  width: 80vw;
  height: 80vh;
  margin: 0 10vmin;
}

.example-box {
  position: absolute;
  width: 200px;
  padding: 10px;
  border-radius: 10px;
  border: 1px solid green;
  cursor: grab;
}

#pos {
  height: 50px;
  padding: 0 10px;
}
<p id="pos">left: 0, top: 0</p>
<div class="example-boundary">
  <div class="example-box" cdkDragBoundary=".example-boundary">
    I can only be dragged within the dotted container
  </div>
</div>

Answer №2

Summary:

I have created two functional examples that meet your requirements. Both examples calculate the top and left positions using a regular expression to capture groups 1 and 2:

transform:\s*translate3d\((.+?),(.+?),.+?\)
.

  1. Cloned DOM: This approach clones the Angular-generated HTML and manually removes unwanted attributes.

  2. Stored data: As per your request, this method stores DOM position, width, height, etc., in a variable and then renders it.


Method #1 (Cloned DOM)

This code snippet clones the Angular-generated HTML and deletes unnecessary attributes manually. More details can be found in the code comments.

If you simply need to re-render a dragged element elsewhere, I recommend this approach as it simplifies attribute management.

Typescript:

// Code here

HTML:

<!-- Code here -->

CSS:

// CSS here

Method #2 (Stored Data)

This method fulfills your specific requirements by storing DOM attributes and rendering them through iteration.

If you plan to customize individual items later on, this method would be more suitable than Method #1.

Typescript:

// Code here

HTML:

<!-- Code here -->

CSS:

// CSS here

Answer №3

Modify the key to trigger a remount of the component.

 <Draggable  key={updatedKey}>   <div/> </Draggable>

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

What is the method for setting up vertical tabs?

Is it possible for someone to provide guidance on how to create vertical tabs for the HTML content below? When a tab, such as tab1 in the left column, is clicked, only the content of tab1 should be displayed in the middle column. The same applies for tab2 ...

Using jQuery to toggle between open and closed states upon clicking

I've been working on a script that allows me to expand an element when clicked, change its content, and then minimize it again with another click Here's the jQuery code I came up with: $(".servicereadmore").click(function () { $('.myin ...

I've decided to create a new Angular app using Yeoman. I've noticed that there are more installed Node modules than what is listed in the package.json file. Is this typical

As a newcomer to Yeoman, I've observed that the node modules in my projects are resembling those in other projects and also the node modules at the root path for node on my laptop. I'm uncertain whether this is due to an issue with my setup or if ...

Deploying CSS/JS files in Magento 2 is a crucial

Hello, I recently set up magento2 with the sample data included. After attempting to deploy static css/JS using the command php bin/magento setup:static-content:deploy, I didn't receive any errors but the issue persists. Additionally, I am unable to l ...

Generate a compressed file from a readable source, insert a new document, and transfer the output

The objective is to obtain an archive from the client, include a file, and transfer it to Cloud Storage without generating a temporary file. Both the client and server utilize the archiver library. The issue with the code snippet provided is that the file ...

Clickable tab to collapse a section containing an image and aligned text

When using Bootstrap 3, I have a button that collapses a div containing an image and text. The button alternates between showing a '+ More' and a '- Less' message. However, the alignment of the image is off with the text. Is there a way ...

The Karma testing feature in Angular Quickstart encounters issues right from the start

When attempting to run karma tests after a clean install of the official Angular quickstart on Windows 10, I encountered an issue. Following a series of four commands, here is what happened: C:\projects\temp>git clone https://github.com/angul ...

Is it possible to run Node and Apache on the same port concurrently?

Currently, I have an application running on Node.js and PHP. I am using different ports for each. Is it possible to run both Node and Apache on the same port 8080? Is there any method to run multiple applications on port 8080 simultaneously? Thank you. ...

Dynamic count down using JavaScript or jQuery

I am looking for a way to create a countdown timer that I can adjust the time interval for in my database. Basically, I have a timestamp in my database table that might change, and I want to check it every 30 seconds and update my countdown accordingly. H ...

What causes the Element to be null in Vue.js?

Could someone please clarify why the console.log output is showing as null, and provide guidance on how to resolve this issue? <template v-for="day in getMonthLength()"> <td> <input :id="day" type=number :value=&qu ...

Encountering a passport error in Node.js - how to troubleshoot and

I'm currently experimenting with using passport in Node for some basic tests. Whenever I attempt to access the route localhost:3000/login, I encounter a Bad Request 400 error. Here's the snippet of code that is causing the issue: var express = r ...

Navigating through nested routes in Express.js and extracting parameters may seem daunting at first, but

In my routing setup, I have defined it as shown below: export const router = Router(); const appRoutes = [ { path: "/", router: usersRouter, }, { path: "/games/", router: gamesRouter, }, { path: "/gam ...

Toggle the state of a Material UI checkbox in ReactJS based on the data from hooks that return a true or checked value

I need assistance with checking/unchecking a checkbox value in an edit modal based on the return of addAdvisory(hooks) which is 'Y', indicating true/checked. Below is my basic code snippet: const [addAdvisory, setaddAdvisory] = useState({ SY ...

Modify the hue of the div as soon as a button on a separate webpage is

Looking for assistance with a page called "diagnosticoST" that contains four buttons (btn-institucional, btn-economico, btn-social, btn-natural). These buttons have different background colors until the survey inside them is completed. Once the user comple ...

Link a YAML file with interfaces in JavaScript

I'm currently learning JavaScript and need to convert a YAML file to an Interface in JavaScript. Here is an example of the YAML file: - provider_name: SEA-AD consortiumn_name: SEA-AD defaults: thumbnail Donors: - id: "https://portal.brain ...

The process of updating a nested object property in Redux and React

Initially, the user object is established with properties such as name, color, and age using the SET_USER method. I need to modify the name property within the user object utilizing UPDATE_USER_NAME. However, despite trying a nested loop within UPDATE_USER ...

"The authentication cookie fields are not defined when trying to get the authentication in the Express framework

After setting up my React client on port 3000 and Express on port 5000, I encountered an issue. When logging in, the cookie fields are set without any problems. However, when trying to retrieve the isauth value, it shows as undefined. //login log message ...

Expanding Vue JS Vuetify Panels in a V-for Loop to Reveal Multiple Panels

When pulling data from a database and looping through it in the DOM using a "v-for" loop, I encountered an issue with Vuetify expansion panel components. The problem is that when a user clicks to open one expansion panel, it ends up opening all other panel ...

Switch up between two distinct colors every three elements using a single selector

I have a group of tr items in my list and I want to apply CSS styles to them in a specific pattern : red red red black black black red red red black and so on. Is there a way to achieve this using just one selector? Currently, I'm doing it like th ...

Detect errors in the `valueChanges` subscription of Firestore and attempt a retry if an error occurs

My Angular app utilizes Firestore for storing data. I have a service set up to retrieve data in the following way: fetchCollectionColors(name) { this.db.collectionGroup('collection-colors', ref => ref.where('product', '==&ap ...