Venk
Venk

Reputation: 230

HTML Table columns inserted with append() not giving expected behaviour

I'm trying to make an interactive table-grid that when you resize the edges, the other tables will be resized too. So far, everything seems to work up until the point where in order to add a new column, you must click the button.

Expected behaviour:

If you try dragging the edges of the initial two columns, they work perfectly. However, if you add a new column by clicking on the button, the column gets added to the table, but does not match the behaviour of the other two. How can I get all columns added with a button to follow the same behaviour?

$(document).ready(function() {
  AddListeners()

  function AddListeners() {
    var thElm;
    var startOffsetX;
    var startOffsetY;

    Array.prototype.forEach.call(
      document.querySelectorAll("table th"),
      function(th) {
        th.style.position = 'relative';

        var grip = document.createElement('div');
        grip.innerHTML = " ";
        grip.style.top = 0;
        grip.style.right = 0;
        grip.style.bottom = 0;
        grip.style.width = '5px';
        grip.style.position = 'absolute';
        grip.style.cursor = 'col-resize';
        grip.addEventListener('mousedown', function(e) {
          thElm = th;
          startOffsetX = th.offsetWidth - e.pageX;
          startOffsetY = th.offsetHeight - e.pageY;
        });

        th.appendChild(grip);
      });

    document.addEventListener('mousemove', function(e) {
      if (thElm) {
        thElm.style.width = startOffsetX + e.pageX + 'px';
        thElm.style.height = startOffsetY + e.pageY + 'px';
      }
    });

    document.addEventListener('mouseup', function() {
      thElm = undefined;
    });
  };
})

var iter = 2;

function AddColumn() {
  var myform = $('#myTable');
  myform.find('tr').each(function() {
    var trow = $(this);
    iter += 1;
    if (trow.index() === 0) {
      trow.append('<th><div style="top: 0px; right: 0px; bottom: 0px; width: 5px; position: absolute; cursor: col-resize;">&nbsp;</div>th ' + iter + '</th>');
    } else {
      trow.append('<td>th ' + iter + '</td>');
    }
  });
}
table {
  border-width: 1px;
  border-style: solid;
  border-color: black;
  border-collapse: collapse;
}

table td {
  border-width: 1px;
  border-style: solid;
  border-color: black;
}

table th {
  border-width: 1px;
  border-style: solid;
  border-color: black;
  background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<a onclick="AddColumn()">Add column</a>

<table id="myTable">
  <thead>
    <tr>
      <th>th 1</th>
      <th>th 2</th>
    </tr>
  </thead>
</table>

Upvotes: 2

Views: 76

Answers (1)

SdtElectronics
SdtElectronics

Reputation: 586

Your code doesn't work because event listeners are only attached to the initial two columns when callback for $(document).ready is called. A simple solution is calling AddListeners() each time when a new column is inserted, as shown below:

function AddListeners() {
    var thElm;
    var startOffsetX;
    var startOffsetY;

    Array.prototype.forEach.call(
      document.querySelectorAll("table th"),
      function(th) {
        th.style.position = 'relative';

        var grip = document.createElement('div');
        grip.innerHTML = "&nbsp;";
        grip.style.top = 0;
        grip.style.right = 0;
        grip.style.bottom = 0;
        grip.style.width = '5px';
        grip.style.position = 'absolute';
        grip.style.cursor = 'col-resize';
        grip.addEventListener('mousedown', function(e) {
          thElm = th;
          startOffsetX = th.offsetWidth - e.pageX;
          startOffsetY = th.offsetHeight - e.pageY;
        });

        th.appendChild(grip);
      });

    document.addEventListener('mousemove', function(e) {
      if (thElm) {
        thElm.style.width = startOffsetX + e.pageX + 'px';
        thElm.style.height = startOffsetY + e.pageY + 'px';
      }
    });

    document.addEventListener('mouseup', function() {
      thElm = undefined;
    });
  };

$(document).ready(function() {
  AddListeners();

  
})

var iter = 2;

function AddColumn() {
  var myform = $('#myTable');
  myform.find('tr').each(function() {
    var trow = $(this);
    iter += 1;
    if (trow.index() === 0) {
      trow.append('<th><div style="top: 0px; right: 0px; bottom: 0px; width: 5px; position: absolute; cursor: col-resize;">&nbsp;</div>th ' + iter + '</th>');
    } else {
      trow.append('<td>th ' + iter + '</td>');
    }
  });
  AddListeners();
}
table {
  border-width: 1px;
  border-style: solid;
  border-color: black;
  border-collapse: collapse;
}

table td {
  border-width: 1px;
  border-style: solid;
  border-color: black;
}

table th {
  border-width: 1px;
  border-style: solid;
  border-color: black;
  background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<a onclick="AddColumn()">Add column</a>

<table id="myTable">
  <thead>
    <tr>
      <th>th 1</th>
      <th>th 2</th>
    </tr>
  </thead>
</table>

This solution is ugly though, since it will redo the listener adding for early existed columns. A better solution would require you to decouple the event attaching procedure for each column from callback in AddListeners() , and call it in Array.prototype.forEach.call and AddColumn() respectively. That's another question though.

Upvotes: 2

Related Questions