Search code examples
javascripthtmlangulardrag-and-drop

Is there a way to move HTML between bowser tabs in Angular?


I am trying to build an Angular (v17) application which lets the user to move around with drag and drop HTML elements, even between multiple browser tabs. Similarly to what neo.mjs is capable of (here is a demo: https://www.youtube.com/watch?v=-L43hntj3jk).

I am currently using Material cdDrag, and thinking of writing a custom Angular shared web worker for this but it will be quite difficult if even possible.

Is there an easier way, or even a 3rd party package with which I could achieve this? Or could I somehow implement neo.mjs into my Angular application?

The project has to be Angular (client request).


Solution

  • In this example I have a draggable <li> element and an iframe (the iframe is just to show that you can drag from one document to another). In the parent document, on dragstart I set data on the dataTransfer object to the HTML code being dragged (the <li> element). In the iframe there are handlers for both dragover and drop. When you drop the <li> the HTML will be added to the <ul> in the iframe. Below is the HTML for the iframe.

    You can try to open the iframe document (the data URI string) in a separate tab, and test if you can drag the <li> from the example here to that tab.

    document.querySelector('ul').addEventListener('dragstart', e => {
      e.dataTransfer.setData("text/html", e.target.outerHTML);
    });
    body {
      display: flex;
    }
    <ul>
      <li draggable="true">Item 1</li>
      <li draggable="true">Item 2</li>
    </ul>
    
    <iframe src="data:text/html;base64,PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KPHNjcmlwdD4KZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsIGUgPT4gewogIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ3VsJykuYWRkRXZlbnRMaXN0ZW5lcignZHJhZ292ZXInLCBlID0+IHsKICAgIGUucHJldmVudERlZmF1bHQoKTsKICAgIGUuZGF0YVRyYW5zZmVyLmRyb3BFZmZlY3QgPSAibW92ZSI7CiAgfSk7CgogIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJ3VsJykuYWRkRXZlbnRMaXN0ZW5lcignZHJvcCcsIGUgPT4gewogICAgZS5wcmV2ZW50RGVmYXVsdCgpOwogICAgZS50YXJnZXQuaW5uZXJIVE1MICs9IGUuZGF0YVRyYW5zZmVyLmdldERhdGEoInRleHQvaHRtbCIpOwogIH0pOwp9KTsKPC9zY3JpcHQ+CjxzdHlsZT4KdWwge21pbi1oZWlnaHQ6IDNlbTsgYm9yZGVyOiB0aGluIGRvdHRlZCBncmF5O30KPC9zdHlsZT4KPC9oZWFkPgo8Ym9keT4KPGRpdj5Ecm9wIHpvbmU6PC9kaXY+Cjx1bD4KPC91bD4KPC9ib2R5Pgo8L2h0bWw+"></iframe>

    Iframe document:

    <!DOCTYPE html>
    <html>
    <head>
    <script>
    document.addEventListener('DOMContentLoaded', e => {
      document.querySelector('ul').addEventListener('dragover', e => {
        e.preventDefault();
        e.dataTransfer.dropEffect = "move";
      });
    
      document.querySelector('ul').addEventListener('drop', e => {
        e.preventDefault();
        e.target.innerHTML += e.dataTransfer.getData("text/html");
      });
    });
    </script>
    <style>
    ul {min-height: 3em; border: thin dotted gray;}
    </style>
    </head>
    <body>
    <div>Drop zone:</div>
    <ul>
    </ul>
    </body>
    </html>