Search code examples
javascriptdraggablehtml5-draggable

HTML5 Draggable List - multiple setData?


So, I have a list of bands that I want to organise into a running order, like so:

<li data-band-id='1' draggable='true' class='band-name'>Metallica</li>
<li data-band-id='2' draggable='true' class='band-name'>Slayer</li>
<li data-band-id='3' draggable='true' class='band-name'>Paradise Lost</li>
<li data-band-id='4' draggable='true' class='band-name'>Gojira</li>

I would like to be able to drag these list items around to change each bands placement within the overall list. So far, I have the following JavaScript to do this:

var dragSatMS = null;
function handleDragStart(e) {
    //this.style.color = 'green'; 
    dragSatMS = this;
    e.dataTransfer.effectAllowed = 'move';
    e.dataTransfer.setData('text', this.innerHTML);
}
function handleDragOver(e) {
    if (e.preventDefault) {
        e.preventDefault(); 
    }
    e.dataTransfer.dropEffect = 'move';
    return false;
}
function handleDragEnter(e) {
    this.classList.add('over');
}
function handleDragLeave(e) {
  this.classList.remove('over');
  //this.style.color = '#333';
}
function handleDrop(e) {
  if (e.stopPropagation) {
    e.stopPropagation();
  }
  if (dragSatMS != this) {
    dragSatMS.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text');
  }
  return false;
}
function handleDragEnd(e) {
  [].forEach.call(mssatCols, function (mSatCol) {
    mSatCol.classList.remove('over');
     //mSatCol.style.color = '#333';
  });
}
var mssatCols = document.querySelectorAll('#ms-saturday .band-name');
[].forEach.call(mssatCols, function(msSatCol) {
  msSatCol.addEventListener('dragstart', handleDragStart, false);
  msSatCol.addEventListener('dragenter', handleDragEnter, false);
  msSatCol.addEventListener('dragover', handleDragOver, false);
  msSatCol.addEventListener('dragleave', handleDragLeave, false);
  msSatCol.addEventListener('drop', handleDrop, false);
  msSatCol.addEventListener('dragend', handleDragEnd, false);
});

This works perfectly, I can drag and drop lists to make them change places and the name of the band swaps appropriately. However, the value of the 'data-band-id' attribute stays as it was. I know this is exactly what the code I have does and thats my issue. I'd like to amend the code so that both the name of the band being dragged and dropped and the value of the 'data-band-id' attribute are swapped.

I've Googled a lot but found nothing that can show me how to setData on multiple values, any help much appreciated.


Solution

  • You can query the attributes property of both items and access the value of data-band-id. Once you have both two values, you can call setAttribute("name", "value") to update the data-band-id. Your updated handleDrop method would then be:

    function handleDrop(e) {
      if (e.stopPropagation) {
        e.stopPropagation();
      }
      if (dragSatMS != this) {
        dragSatMS.innerHTML = this.innerHTML;
        this.innerHTML = e.dataTransfer.getData('text');
        //Get the data-band-id of both items.
        itemToReplaceAttr = this.attributes["data-band-id"].value;
        draggedItemAttr = dragSatMS.attributes["data-band-id"].value;
        //Call "setAttribute" to update the attributes.
        this.setAttribute("data-band-id", draggedItemAttr);
        dragSatMS.setAttribute("data-band-id", itemToReplaceAttr);
      }
      return false;
    }
    

    Here's a demo for good measure: Fiddle