Dragging and Dropping Multiple Items

  • Revision slug: DragDrop/Dragging_and_Dropping_Multiple_Items
  • Revision title: Dragging and Dropping Multiple Items
  • Revision id: 111670
  • Created:
  • Creator: Enn
  • Is current revision? No
  • Comment 1 words added

Revision Content

Mozilla supports the ability to drag multiple items using some additional non-standard methods. These are methods that mirror the types property as well as the getData, setData and clearData, however, they take an additional argument that specifies the index of the item to retrieve, modify or remove.

The mozSetDataAt allows you to add multiple items during a dragstart event. This functions similarly to the setData method.

var dt = event.dataTransfer;
dt.mozSetDataAt("text/plain", "Data to drag", 0);
dt.mozSetDataAt("text/plain", "Second data to drag", 1);

This example adds two items to be dragged. The last argument specifies the index of the item to add. You should add them in order starting with 0 as you cannot add items at positions farther than the last item, however you can replace existing items by using indices you have already added. Using 0 as the index is equivalent to calling the setData method.

You can clear an item using the mozClearDataAt method.

event.dataTransfer.mozClearDataAt("text/plain", 1);

Be careful as removing the last format for a particular index with remove that item entirely, shifting the remaining items down, so the later items will have different indices. Fortunately, you don't normally need to clear items often; it's more common to just add the items only when you know they are needed.

Common cases where dragging multiple items is used is when dragging multiple files or bookmarks. In this case, add the appropriate formats for each item. Although not required, you should always add the same formats for each item. The ensures that receiving drop targets can expect consistent data.

To check if multiple files are being dragged, check the mozItemCount property. It will be set to the number of items being dragged. If a particular drop target only supports dropping a single item, it could either reject the dragged items or it could just use just the first item. To reject the items, either don't cancel the dragover event, or set the effectAllowed property to node. You may wish to do both in case another listener has already cancelled the event.

To just take the first item being dropped, use the getData as with single items. This is convenient as drop targets which only need to support single items do not need to do anything extra.

However, use the mozGetDataAt to retrieve a specific item from the data transfer. The following example retrieves a set of files being dragged and adds them to an array.

function onDrop(event)
{
  var files = [];
  var dt = event.dataTransfer;
  for (var i = 0; i dt.mozItemCount; dt++)
    files.push(dt.mozGetDataAt("application/x-moz-file", i));
}

You may also wish to check if the desired format exists using the mozTypesAt method. As with the types, it returns a list of strings of the types for an item. The types property is equivalent to retrieving the list of types for the item at index 0.

var types = event.dataTransfer.mozTypesAt(1);

Dragging Non-String Data

The additional methods described above are also not restricted to string data; you can specify any type of data. For example, files are dragged using the application/x-moz-file type stored as nsIFile objects. As the setData method only supports strings, it cannot be used to specify files for dragging in this manner. Instead the mozSetDataAt method must be used.

dt.mozSetDataAt("application/x-moz-file", file, 0);

By using this method, you can file objects, although you do not necessarily need to support multiple items. Thus, you should pass 0 as the index.

Similarly, you will need to retrieve the file object or objects using the mozGetDataAt method. If you use the getData, you will receive an empty string as the data is not a string. Note that some simple types like numbers can be converted to strings, so it is safe to use getData in this case.

Multiple Drop Example

The following example provides a box where the lists of items and formats dropped on it are displayed.

<html>
<head>
<script>

function dodrop(event)
{
  var dt = event.dataTransfer;
  var count = dt.mozItemCount;
  output("Items: " + count + "\n");

  for (var i = 0; i < count; i++) {
    output(" Item " + i + ":\n");
    var types = dt.mozTypesAt(i);
    for (var t = 0; t < types.length; t++) {
      output("  " + types[t] + ": ");
      try {
        var data = dt.mozGetDataAt(types[t], i);
        output("(" + (typeof data) + ") : <" + data + " >\n");
      } catch (ex) {
        output("<<error>>\n");
        dump(ex);
      }
    }
  }
}

function output(text)
{
  document.getElementById("output").textContent += text;
  dump(text);
}

</script>
</head>
<body>

<div id="output" style="min-height: 100px; white-space: pre; border: 1px solid black;"
     ondragenter="document.getElementById('output').textContent = ''; event.stopPropagation(); event.preventDefault();"
     ondragover="event.stopPropagation(); event.preventDefault();"
     ondrop="event.stopPropagation(); event.preventDefault(); dodrop(event);">
<div>

</body>
</html>
</error>

This example cancels both the dragenter and dragover events by calling the preventDefault. method. This allows a drop to occur on that element.

The dodrop method is called when dropping an item. It checks the mozItemCount property to check how many items have been dropped and iterates over them. For each item, the mozTypesAt method is called to get the list of types. This list is iterated over to get all of the data associated with the drag.

This example is useful is you wish to examine the data that a drag is holding. Simply drop an item on the drop target in the example to see what items, formats and data was being dragged.

Revision Source

<p>Mozilla supports the ability to drag multiple items using some additional non-standard methods. These are methods that mirror the <a href="/En/DragDrop/DataTransfer#types.28.29" title="types">types</a> property as well as the <a href="/En/DragDrop/DataTransfer#getData.28.29" title="getData">getData</a>, <a href="/En/DragDrop/DataTransfer#setData.28.29" title="setData">setData</a> and <a href="/En/DragDrop/DataTransfer#clearData.28.29" title="clearData">clearData</a>, however, they take an additional argument that specifies the index of the item to retrieve, modify or remove.</p>
<p>The <a href="/En/DragDrop/DataTransfer#mozSetDataAt.28.29" title="mozSetDataAt">mozSetDataAt</a> allows you to add multiple items during a <code>dragstart</code> event. This functions similarly to the <a href="/En/DragDrop/DataTransfer#setData.28.29" title="setData">setData</a> method.</p>
<pre>var dt = event.dataTransfer;
dt.mozSetDataAt("text/plain", "Data to drag", 0);
dt.mozSetDataAt("text/plain", "Second data to drag", 1);
</pre>
<p>This example adds two items to be dragged. The last argument specifies the index of the item to add. You should add them in order starting with 0 as you cannot add items at positions farther than the last item, however you can replace existing items by using indices you have already added. Using 0 as the index is equivalent to calling the <a href="/En/DragDrop/DataTransfer#setData.28.29" title="setData">setData</a> method.</p>
<p>You can clear an item using the <a href="/En/DragDrop/DataTransfer#mozClearDataAt.28.29" title="mozClearDataAt">mozClearDataAt</a> method.</p>
<pre>event.dataTransfer.mozClearDataAt("text/plain", 1);
</pre>
<p>Be careful as removing the last format for a particular index with remove that item entirely, shifting the remaining items down, so the later items will have different indices. Fortunately, you don't normally need to clear items often; it's more common to just add the items only when you know they are needed.</p>
<p>Common cases where dragging multiple items is used is when dragging multiple files or bookmarks. In this case, add the appropriate formats for each item. Although not required, you should always add the same formats for each item. The ensures that receiving drop targets can expect consistent data.</p>
<p>To check if multiple files are being dragged, check the <a href="/En/DragDrop/DataTransfer#mozItemCount.28.29" title="mozItemCount">mozItemCount</a> property. It will be set to the number of items being dragged. If a particular drop target only supports dropping a single item, it could either reject the dragged items or it could just use just the first item. To reject the items, either don't cancel the dragover event, or set the <a href="/En/DragDrop/DataTransfer#effectAllowed.28.29" title="effectAllowed">effectAllowed</a> property to <code>node</code>. You may wish to do both in case another listener has already cancelled the event.</p>
<p>To just take the first item being dropped, use the <a href="/En/DragDrop/DataTransfer#getData.28.29" title="getData">getData</a> as with single items. This is convenient as drop targets which only need to support single items do not need to do anything extra.</p>
<p>However, use the <a href="/En/DragDrop/DataTransfer#mozGetDataAt.28.29" title="mozGetDataAt">mozGetDataAt</a> to retrieve a specific item from the data transfer. The following example retrieves a set of files being dragged and adds them to an array.</p>
<pre>function onDrop(event)
{
  var files = [];
  var dt = event.dataTransfer;
  for (var i = 0; i dt.mozItemCount; dt++)
    files.push(dt.mozGetDataAt("application/x-moz-file", i));
}
</pre>
<p>You may also wish to check if the desired format exists using the <a href="/En/DragDrop/DataTransfer#mozTypesAt.28.29" title="mozTypesAt">mozTypesAt</a> method. As with the <a href="/En/DragDrop/DataTransfer#types.28.29" title="types">types</a>, it returns a list of strings of the types for an item. The <a href="/En/DragDrop/DataTransfer#types.28.29" title="types">types</a> property is equivalent to retrieving the list of types for the item at index 0.</p>
<pre>var types = event.dataTransfer.mozTypesAt(1);
</pre>
<h2>Dragging Non-String Data</h2>
<p>The additional methods described above are also not restricted to string data; you can specify any type of data. For example, files are dragged using the <a href="/En/DragDrop/Recommended_Drag_Types#file" title="application/x-moz-file">application/x-moz-file</a> type stored as <a href="/en/nsIFile" title="nsIFile">nsIFile</a> objects. As the <code>setData</code> method only supports strings, it cannot be used to specify files for dragging in this manner. Instead the <a href="/En/DragDrop/DataTransfer#mozSetDataAt.28.29" title="mozSetDataAt">mozSetDataAt</a> method must be used.</p>
<pre>dt.mozSetDataAt("application/x-moz-file", file, 0);
</pre>
<p>By using this method, you can file objects, although you do not necessarily need to support multiple items. Thus, you should pass 0 as the index.</p>
<p>Similarly, you will need to retrieve the file object or objects using the <a href="/En/DragDrop/DataTransfer#mozGetDataAt.28.29" title="mozGetDataAt">mozGetDataAt</a> method. If you use the <a href="/En/DragDrop/DataTransfer#getData.28.29" title="getData">getData</a>, you will receive an empty string as the data is not a string. Note that some simple types like numbers can be converted to strings, so it is safe to use <a href="/En/DragDrop/DataTransfer#getData.28.29" title="getData">getData</a> in this case.</p><h2>Multiple Drop Example</h2>
<p>The following example provides a box where the lists of items and formats dropped on it are displayed.</p>
<pre>&lt;html&gt;
&lt;head&gt;
&lt;script&gt;

function dodrop(event)
{
  var dt = event.dataTransfer;
  var count = dt.mozItemCount;
  output("Items: " + count + "\n");

  for (var i = 0; i &lt; count; i++) {
    output(" Item " + i + ":\n");
    var types = dt.mozTypesAt(i);
    for (var t = 0; t &lt; types.length; t++) {
      output("  " + types[t] + ": ");
      try {
        var data = dt.mozGetDataAt(types[t], i);
        output("(" + (typeof data) + ") : &lt;" + data + " &gt;\n");
      } catch (ex) {
        output("&lt;&lt;error&gt;&gt;\n");
        dump(ex);
      }
    }
  }
}

function output(text)
{
  document.getElementById("output").textContent += text;
  dump(text);
}

&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div id="output" style="min-height: 100px; white-space: pre; border: 1px solid black;"
     ondragenter="document.getElementById('output').textContent = ''; event.stopPropagation(); event.preventDefault();"
     ondragover="event.stopPropagation(); event.preventDefault();"
     ondrop="event.stopPropagation(); event.preventDefault(); dodrop(event);"&gt;
&lt;div&gt;

&lt;/body&gt;
&lt;/html&gt;
&lt;/error&gt;</pre>
<p>This example cancels both the <code>dragenter</code> and <code>dragover</code> events by calling the <a href="/en/DOM/event.preventDefault" title="en/DOM/event.preventDefault">preventDefault</a>. method. This allows a drop to occur on that element.</p>
<p>The <code>dodrop</code> method is called when dropping an item. It checks the <a href="/En/DragDrop/DataTransfer#mozItemCount.28.29" title="mozItemCount">mozItemCount</a> property to check how many items have been dropped and iterates over them. For each item, the <a href="/En/DragDrop/DataTransfer#mozTypesAt.28.29" title="mozTypesAt">mozTypesAt</a> method is called to get the list of types. This list is iterated over to get all of the data associated with the drag.</p>
<p>This example is useful is you wish to examine the data that a drag is holding. Simply drop an item on the drop target in the example to see what items, formats and data was being dragged.</p>
Revert to this revision