简体   繁体   中英

Identify cell in an HTML5 drag and drop operation on a table

I am playing around with the HTML5 drag and drop feature in an Angular application. I have the following scenario:

  • A container with some 'objects' that can be dragged
  • A table where the user can drop the dragged elements

I've followed the steps in this tutorial: https://medium.com/@mithun_daa/drag-and-drop-in-angular-2-using-native-html5-api-f628ce4edc3b

And I've created the following app: https://stackblitz.com/edit/angular-vhyax1?embed=1&file=src/app/app.component.html

I've applied the 'makeDraggable' directive to the HTML table so it accepts the drop event. I'd like to know if there's a way to identify the table cell where the element is dropped. I know I could add the 'makeDraggable' directive to each TD cell instead of the parent table, but I'd like to avoid it, as the table can have thousands of cells. Is it possible (and worth it in terms of performance)?

Thanks a lot,

Edit: Alternative solution

I just thought that, instead of looking for a pos_id data attribute when traversing the path array, I can look for 'TD' elements (using the tagName property). Similarly, I can get the parent 'TR'. The cells have a cellIndex property, and the rows have a rowIndex , so I can use these values to look for the cell data in the source object from which the table is built.

Original solution

I don't know if this is the best solution, but it worked for me:

First, in the HTML template, I've added to the droppable cells a pos_id data attribute with the ID of that cell. So they look like:

<tr>
  <td data-pos_id="101"> ... </td>
  <td data-pos_id="102"> ... </td>
  ...
<tr>
<tr>
  <td data-pos_id="201"> ... </td>
  <td data-pos_id="202"> ... </td>
  ...
<tr>

Second, in the makeDroppable directive, inside the drop event listener, I use the path / composedPath property/method to get an array of the DOM elements over which the cursor is. Then, I traverse this array looking for an element that has a pos_id dataset attribute, which will be the element that I'm looking for:

el.addEventListener('drop', (e) => {
  ...

  // Event DOM path
  var path = e.path || (e.composedPath && e.composedPath());

  for(let elem of path) {
    // If the element has a data attribute called 'pos_id', it's a droppable <TD>
    if (elem.dataset && elem.dataset.pos_id) { 
      elem.classList.add('over');
      console.log('Dropped object on position '+elem.dataset.pos_id);

      break;
    }
  }

  ...
}

However, this method has a BIG problem: it relies on a dataset attribute to identify uniquely the position where the user dropped the object, so if the user changes this attribute using the developer console or any other method, the application won't work as expected. I'll post a new question about this subject and I'll keep on doing tests to try to solve this issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM