Chris
Chris

Reputation: 12181

Drag and drop example - HTML5

I'm trying to learn the drag and drop example from the WWWC (here) and I can get the list items to be removed from the original list when dragged away, but not appear in the new list. Any ideas why not? I have tried on Safari 5.1.1, Chrome 15, and Firefox 7.0.1.

    <head>
        <title>Drag 'N Drop</title>
    </head>

    <p>What fruits do you like?</p>
    <ol ondragstart="dragStartHandler(event)" ondragend="dragEndHandler(event)">    
     <li draggable="true" data-value="fruit-apple">Apples</li>
     <li draggable="true" data-value="fruit-orange">Oranges</li>
     <li draggable="true" data-value="fruit-pear">Pears</li>
    </ol>
    <script>
      var internalDNDType = 'text/plain'; // set this to something specific to your site
      function dragStartHandler(event) {
        if (event.target instanceof HTMLLIElement) {
          // use the element's data-value="" attribute as the value to be moving:
          event.dataTransfer.setData(internalDNDType, event.target.dataset.value);
          event.dataTransfer.effectAllowed = 'move'; // only allow moves
        } else {
          event.preventDefault(); // don't allow selection to be dragged
        }
      }
      function dragEndHandler(event) {
        // remove the dragged element
        event.target.parentNode.removeChild(event.target);

      }
    </script>

    <p>Drop your favorite fruits below:</p>
    <div dropzone="move s:text/plain" ondrop="dropHandler(event)">
        <ol dropzone="move s:text/plain" ondrop="dropHandler(event)">
         <!-- don't forget to change the "text/x-example" type to something
         specific to your site -->
            <li>Bananas</li>
        </ol>
        </br>
        </br>
        </br>
    </div>
    <script>
      var internalDNDType = 'text/plain'; // set this to something specific to your site
      function dropHandler(event) {
        var li = document.createElement('li');
        var data = event.dataTransfer.getData(internalDNDType);
        if (data == 'fruit-apple') {
          li.textContent = 'Apples';
        } else if (data == 'fruit-orange') {
          li.textContent = 'Oranges';
        } else if (data == 'fruit-pear') {
          li.textContent = 'Pears';
        } else {
          li.textContent = 'Unknown Fruit';
        }
        event.target.appendChild(li);
      }
    </script>

Upvotes: 0

Views: 6977

Answers (2)

Ernest
Ernest

Reputation: 590

The short answer would be that you also need to add a dragover listener to the drop area in order to allow the drop action to happen.

function handleDragOver(e) {
  if (e.preventDefault) {
    e.preventDefault(); // Necessary. Allows us to drop.
  }

  e.dataTransfer.dropEffect = 'move';

  return false;
}

You have a detailed explanation in this step by step tutorial (although the elements in that tutorial act as both draggable elements and drop areas)

However, Chris, as much as I am glad you are experimenting with the native HTML5 drag and drop feature please accept my humble opinion when I say that your code has way too many serious mistakes both at markup level and Javascript level. i.e. missing tags, closing tags that don't exist, wrong attribute namespaces, repeated listeners in chained elements, repeated variables inside the same scope, etc. I'd suggest to go through several code reviews first.

Upvotes: 0

robertc
robertc

Reputation: 75757

There are a couple of issues. First, your dropzone needs to cancel the event on drag over:

<ol dropzone="move s:text/plain" ondrop="dropHandler(event)" ondragover="dragOverHandler(event)">

function dragOverHandler(event) {
    event.preventDefault();
    return false;
}

Second, your dropHandler handler function is going to get fired several times because the drop target, most of the time, is going to be an li element rather than the ol (and possibly also the div, but I ignored that element). So either add code to only handle the event at the ol, or cancel the event in dropHandler with stopPropagation.

Finally, the default action (at least in Firefox, didn't check other browsers) when an item is dropped is to try and navigate to the URL represented by the text/plain value, so you should add some event.preventDefault() in likely places. Here's an updated dropHandler function:

function dropHandler(event) {
    var li = document.createElement('li');
    var data = event.dataTransfer.getData(internalDNDType);
    if (data == 'fruit-apple') {
      li.textContent = 'Apples';
    } else if (data == 'fruit-orange') {
      li.textContent = 'Oranges';
    } else if (data == 'fruit-pear') {
      li.textContent = 'Pears';
    } else {
      li.textContent = 'Unknown Fruit';
    }
    event.target.appendChild(li);
    event.stopPropagation();
    event.preventDefault();
    return false;
}

Here's my updated version.

Upvotes: 2

Related Questions