Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update the displayed number to match its position in the order of elements in pure javascript

Tags:

javascript

I have code that allows me to drag and drop to rearrange items and move them from container to container, but I also want to update the number inside the span tag to match it's position in order.

For example, "Colorado" is in the 0 position, but when I drag it after "Utah" I want to update "Montana" to have "0" next to it, "Utah" to "1", and "Colorado" to "2", but I don't know how to do that.

Here is the JS fiddle: https://jsfiddle.net/benschnell/0wbfoqk9/

const draggables = document.querySelectorAll('.draggable')
const containers = document.querySelectorAll('.container')

draggables.forEach(draggable => {
  draggable.addEventListener('dragstart', () => {
    draggable.classList.add('dragging')
  })

  draggable.addEventListener('dragend', () => {
    draggable.classList.remove('dragging')
  })
})

containers.forEach(container => {
  container.addEventListener('dragover', dragOver);
})

function dragOver(e) {
   e.preventDefault()
    const afterElement = getDragAfterElement(this, e.clientY)
    const draggable = document.querySelector('.dragging')
    if (afterElement == null) {
      this.appendChild(draggable)
    } else {
      this.insertBefore(draggable, afterElement)
    }
}

function getDragAfterElement(container, y) {
  const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')]

  return draggableElements.reduce((closest, child) => {
    const box = child.getBoundingClientRect()
    const offset = y - box.top - box.height / 2
    if (offset < 0 && offset > closest.offset) {
      return { offset: offset, element: child }
    } else {
      return closest
    }
  }, { offset: Number.NEGATIVE_INFINITY }).element
}
<ul class="container">
  <li class="draggable" draggable="true"><span>0</span> Colorado</li>
  <li class="draggable" draggable="true"><span>1</span> Montana</li>
  <li class="draggable" draggable="true"><span>2</span> Utah</li>
  <li class="draggable" draggable="true"><span>3</span> Montana</li>
  <li class="draggable" draggable="true"><span>4</span> Wyoming</li>
</ul>

<ul class="container">
  <li class="draggable" draggable="true"><span>0</span> Maine</li>
  <li class="draggable" draggable="true"><span>1</span> North Carolina</li>
  <li class="draggable" draggable="true"><span>2</span> Florida</li>
  <li class="draggable" draggable="true"><span>3</span> Virginia</li>
  <li class="draggable" draggable="true"><span>4</span> New York</li>
</ul>
like image 465
Ben Schnell Avatar asked Nov 07 '22 05:11

Ben Schnell


1 Answers

You can loop the list elements in each container and renumber them according to their index:

const draggables = document.querySelectorAll('.draggable')
const containers = document.querySelectorAll('.container')

draggables.forEach(draggable => {
  draggable.addEventListener('dragstart', () => {
    draggable.classList.add('dragging')
  })

  draggable.addEventListener('dragend', () => {
    draggable.classList.remove('dragging')
  })
})

containers.forEach(container => {
  container.addEventListener('dragover', dragOver);
})

function dragOver(e) {
  e.preventDefault()
  const afterElement = getDragAfterElement(this, e.clientY)
  const draggable = document.querySelector('.dragging')
  if (afterElement == null) {
    this.appendChild(draggable)
  } else {
    this.insertBefore(draggable, afterElement)
  }
  
  document.querySelectorAll('.container').forEach(c => {
    c.querySelectorAll('li.draggable').forEach((r, i) => {
      r.querySelector('span').innerHTML = i
    })
  })
}

function getDragAfterElement(container, y) {
  const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')]

  return draggableElements.reduce((closest, child) => {
    const box = child.getBoundingClientRect()
    const offset = y - box.top - box.height / 2
    if (offset < 0 && offset > closest.offset) {
      return {
        offset: offset,
        element: child
      }
    } else {
      return closest
    }
  }, {
    offset: Number.NEGATIVE_INFINITY
  }).element
}
<ul class="container">
  <li class="draggable" draggable="true"><span>0</span> Colorado</li>
  <li class="draggable" draggable="true"><span>1</span> Montana</li>
  <li class="draggable" draggable="true"><span>2</span> Utah</li>
  <li class="draggable" draggable="true"><span>3</span> Montana</li>
  <li class="draggable" draggable="true"><span>4</span> Wyoming</li>
</ul>

<ul class="container">
  <li class="draggable" draggable="true"><span>0</span> Maine</li>
  <li class="draggable" draggable="true"><span>1</span> North Carolina</li>
  <li class="draggable" draggable="true"><span>2</span> Florida</li>
  <li class="draggable" draggable="true"><span>3</span> Virginia</li>
  <li class="draggable" draggable="true"><span>4</span> New York</li>
</ul>
like image 137
Brian Lee Avatar answered Nov 14 '22 22:11

Brian Lee