skip to Main Content

I have the following grid:

    <html>
<head>
  <style>
      .grid {
          display: grid;
          grid-template-columns: 100px 100px 100px 100px 100px;
          grid-template-rows: 50px 50px 50px 50px;
          grid-gap: 10px;

          & > * {
              padding: 10px;
              border: 1px solid black;
          }

          & > div:first-child {
              border: none;
          }

          & .column-header {
              background-color: lightgray;
          }

          & .row-header {
              background-color: lightgray;
          }
      }
  </style>
</head>
<body>
<div class="grid">
  <div></div>
  <div class="column-header">Col 1</div>
  <div class="column-header">Col 2</div>
  <div class="column-header">Col 3</div>
  <div class="column-header">Col 4</div>

  <div class="row-header">Row 1</div>
  <div>Cell 1.1</div>
  <div>Cell 2.1</div>
  <div>Cell 3.1</div>
  <div>Cell 4.1</div>

  <div class="row-header">Row 2</div>
  <div>Cell 1.2</div>
  <div>Cell 2.2</div>
  <div>Cell 3.2</div>
  <div>Cell 4.2</div>

  <div class="row-header">Row 3</div>
  <div>Cell 1.3</div>
  <div>Cell 2.3</div>
  <div>Cell 3.3</div>
  <div>Cell 4.3</div>

  <div class="row-header">Row 4</div>
  <div>Cell 1.4</div>
  <div>Cell 2.4</div>
  <div>Cell 3.4</div>
  <div>Cell 4.4</div>
</div>
</body>
</head>

How to use Javascript drag and drop api to:

  1. drag any of the "Column headers" cells and rearrange the columns horizontally
  2. drag any of the "Row headers" cells and rearrange the rows vertically

?

2

Answers


  1. Maybe this could help: Try to set some custom attribute to column and row headers, like draggable to true

    The grid structure assumes that each cell is an independent element. Rearranging rows or columns involves swapping content rather than rearranging the DOM structure. This solution is suitable for simple grids. I am not sure how complex your grid is.

    Here is the working example which is a good start.

    Do you want to rearrange the whole row and columns or just the headers?

    Let me know if I can assist you further.

    Login or Signup to reply.
  2. I have put together this example:

    • First, set the draggable attribute to true for all headers.

    • Then you need to handle each drag event. See HTMLElement: dragstart event.

    • Lastly, you need to swap rows/columns.

    Here is a working example (of course, you need to adjust hardcoded values or make it dynamic for your application):

    let dragSrcEl = null;
    
    function handleDragStart(e) {
      this.style.opacity = '0.4';
      dragSrcEl = this;
      e.dataTransfer.effectAllowed = 'move';
      e.dataTransfer.setData('text/html', this.innerHTML);
    }
    
    function handleDragEnd() {
      this.style.opacity = '1';
      items.forEach(function(item) {
        item.classList.remove('over');
      });
    }
    
    function handleDragOver(e) {
      if (e.preventDefault) {
        e.preventDefault();
      }
      return false;
    }
    
    function handleDragEnter() {
      this.classList.add('over');
    }
    
    function handleDragLeave() {
      this.classList.remove('over');
    }
    
    function handleDrop(e) {
      if (e.stopPropagation) {
        e.stopPropagation();
      }
      if (dragSrcEl !== this) {
        if (dragSrcEl.classList.contains('column-header') && this.classList.contains('column-header')) {
          swapColumns(dragSrcEl, this);
        } else if (dragSrcEl.classList.contains('row-header') && this.classList.contains('row-header')) {
          swapRows(dragSrcEl, this);
        }
      }
      return false;
    }
    
    function swapColumns(src, dest) {
      const srcIndex = Array.from(src.parentNode.children).indexOf(src);
      const destIndex = Array.from(dest.parentNode.children).indexOf(dest);
    
      const grid = document.querySelector('.grid');
      for (let i = 0; i < grid.children.length; i++) {
        if (i % 5 === srcIndex) {
          const temp = grid.children[i].innerHTML;
          grid.children[i].innerHTML = grid.children[i + (destIndex - srcIndex)].innerHTML;
          grid.children[i + (destIndex - srcIndex)].innerHTML = temp;
        }
      }
    }
    
    function swapRows(src, dest) {
      const srcIndex = Array.from(src.parentNode.children).indexOf(src) / 5;
      const destIndex = Array.from(dest.parentNode.children).indexOf(dest) / 5;
    
      const grid = document.querySelector('.grid');
      for (let i = 0; i < 5; i++) {
        const temp = grid.children[srcIndex * 5 + i].innerHTML;
        grid.children[srcIndex * 5 + i].innerHTML = grid.children[destIndex * 5 + i].innerHTML;
        grid.children[destIndex * 5 + i].innerHTML = temp;
      }
    }
    
    let items = document.querySelectorAll('.grid .column-header, .grid .row-header');
    items.forEach(function(item) {
      item.addEventListener('dragstart', handleDragStart);
      item.addEventListener('dragover', handleDragOver);
      item.addEventListener('dragenter', handleDragEnter);
      item.addEventListener('dragleave', handleDragLeave);
      item.addEventListener('dragend', handleDragEnd);
      item.addEventListener('drop', handleDrop);
    });
    .grid {
      display: grid;
      grid-template-columns: 100px 100px 100px 100px 100px;
      grid-template-rows: 50px 50px 50px 50px;
      grid-gap: 10px;
    }
    
    .grid>* {
      padding: 10px;
      border: 1px solid black;
    }
    
    .grid>div:first-child {
      border: none;
    }
    
    .column-header,
    .row-header {
      background-color: lightgray;
      cursor: move;
    }
    <div class="grid">
      <div></div>
      <div class="column-header" draggable="true">Col 1</div>
      <div class="column-header" draggable="true">Col 2</div>
      <div class="column-header" draggable="true">Col 3</div>
      <div class="column-header" draggable="true">Col 4</div>
    
      <div class="row-header" draggable="true">Row 1</div>
      <div>Cell 1.1</div>
      <div>Cell 2.1</div>
      <div>Cell 3.1</div>
      <div>Cell 4.1</div>
    
      <div class="row-header" draggable="true">Row 2</div>
      <div>Cell 1.2</div>
      <div>Cell 2.2</div>
      <div>Cell 3.2</div>
      <div>Cell 4.2</div>
    
      <div class="row-header" draggable="true">Row 3</div>
      <div>Cell 1.3</div>
      <div>Cell 2.3</div>
      <div>Cell 3.3</div>
      <div>Cell 4.3</div>
    
      <div class="row-header" draggable="true">Row 4</div>
      <div>Cell 1.4</div>
      <div>Cell 2.4</div>
      <div>Cell 3.4</div>
      <div>Cell 4.4</div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search