3
votes

For a html table, I am trying to achieve 100% container height along with table column resize functionality. I.e., only the tbody should scroll when content height exceeds containing div's height(not thead and tfoot). And it should be possible to resize table columns. For some reason I want to use only one table element(I don't want to achieve this by using separate tables for thead and tbody).

I have tried the following fiddles based on the suggestions given here

These are the fiddles I tried

1.http://jsfiddle.net/Ld4uv0a4/2/

table.scroll {
    /* width: 100%; */ /* Optional */
    /* border-collapse: collapse; */
    border-spacing: 0;
    border: 2px solid black;
}

table.scroll tbody,
table.scroll thead { display: block; }

thead tr th { 
    height: 30px;
    line-height: 30px;
    /* text-align: left; */
}

table.scroll tbody {
    height: 100px;
    overflow-y: auto;
    overflow-x: hidden;
}

tbody { border-top: 2px solid black; }

tbody td, thead th {
    /* width: 20%; */ /* Optional */
    border-right: 1px solid black;
    /* white-space: nowrap; */
}

tbody td:last-child, thead th:last-child {
    border-right: none;
}

2.https://jsfiddle.net/wwjgozqp/

.table-container {
    height: 10em;
}
table {
    display: flex;
    flex-flow: column;
    height: 100%;
    width: 100%;
}
table thead {
    /* head takes the height it requires, 
    and it's not scaled when table is resized */
    flex: 0 0 auto;
    width: calc(100% - 0.9em);
}
table tbody {
    /* body takes all the remaining available space */
    flex: 1 1 auto;
    display: block;
    overflow-y: scroll;
}
table tbody tr {
    width: 100%;
}
table thead,
table tbody tr {
    display: table;
    table-layout: fixed;
}
/* decorations */
.table-container {
    border: 1px solid black;
    padding: 0.3em;
}
table {
    border: 1px solid lightgrey;
}
table td, table th {
    padding: 0.3em;
    border: 1px solid lightgrey;
}
table th {
    border: 1px solid grey;
}

But nothing seems to work. Could anyone help me in achieving these two effects (column resize and 100% container height).

1

1 Answers

1
votes

You need to update the respective columns as well when you resize the column header.

Here is what you could do. It might need some fine tuning , but you could use this as a starting point.

//following code is used for column resize
$(function() {
  $("table").find("th").each(function(i, item) {
    var $th = $(this);
    var text = $th.text();
    $th.html("");
    var $colHandle = $("<div class='colHandle'></div>");
    var colResizer = $("<div class='colResizer'></div>").html(text).append($colHandle);
    $th.append(colResizer);
    $colHandle.mousedown(function(e) {
      var startX = e.clientX;
      $(document).bind("mousemove", function(e) {
        var width = $th.width() + (e.clientX - startX);
        $th.width(width);
        var idx = $th.index() + 1;
        $("table tr td:nth-of-type(" + idx + ")").width(width);
        startX = e.clientX;
      });
      $(document).mouseup(function() {
        $(document).unbind("mousemove");
      });
    });

  });

});
.table-container {
  height: 10em;
}
table {
  display: flex;
  flex-flow: column;
  height: 100%;
  width: 100%;
}
table thead {
  /* head takes the height it requires, 
    and it's not scaled when table is resized */
  flex: 0 0 auto;
  width: calc(100% - 0.9em);
}
table tbody {
  /* body takes all the remaining available space */
  flex: 1 1 auto;
  display: block;
  overflow-y: scroll;
}
table tbody tr {
  width: 100%;
}
table thead,
table tbody tr {
  display: table;
  table-layout: fixed;
}
/* decorations */

.table-container {
  border: 1px solid black;
  padding: 0.3em;
}
table {
  border: 1px solid lightgrey;
}
table td,
table th {
  padding: 0.3em;
  border: 1px solid lightgrey;
}
table th {
  border: 1px solid grey;
}
.colResizer {
  background-color: red;
  position: relative;
  cursor: e-resize;
}
.colHandle {
  height: 20px;
  width: 20px;
  background-color: transparent;
  position: absolute;
  right: -10px;
  top: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="table-container">
  <table>
    <thead>
      <tr>
        <th>head1</th>
        <th>head2</th>
        <th>head3</th>
        <th>head4</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>content1</td>
        <td>content2</td>
        <td>content3</td>
        <td>content4</td>
      </tr>
      <tr>
        <td>content1</td>
        <td>content2</td>
        <td>content3</td>
        <td>content4</td>
      </tr>
      <tr>
        <td>content1</td>
        <td>content2</td>
        <td>content3</td>
        <td>content4</td>
      </tr>
      <tr>
        <td>content1</td>
        <td>content2</td>
        <td>content3</td>
        <td>content4</td>
      </tr>
      <tr>
        <td>content1</td>
        <td>content2</td>
        <td>content3</td>
        <td>content4</td>
      </tr>
      <tr>
        <td>content1</td>
        <td>content2</td>
        <td>content3</td>
        <td>content4</td>
      </tr>
    </tbody>
  </table>
</div>

// Change the selector if needed
var $table = $('table.scroll'),
  $bodyCells = $table.find('tbody tr:first').children(),
  colWidth;

// Adjust the width of thead cells when window resizes
$(window).resize(function() {
  // Get the tbody columns width array
  colWidth = $bodyCells.map(function() {
    return $(this).width();
  }).get();

  // Set the width of thead columns
  $table.find('thead tr').children().each(function(i, v) {
    $(v).width(colWidth[i]);
  });
}).resize(); // Trigger resize handler

//following code is used for column resize
$(function() {
  $("table").find("th").each(function(i, item) {
    var $th = $(this);
    var text = $th.text();
    $th.html("");
    var $colHandle = $("<div class='colHandle'></div>");
    var colResizer = $("<div class='colResizer'></div>").html(text).append($colHandle);
    $th.append(colResizer);
    $colHandle.mousedown(function(e) {
      var startX = e.clientX;
      $(document).bind("mousemove", function(e) {
        let width = $th.width() + (e.clientX - startX);
        $th.width(width);
        let idx = $th.index() + 1;
        startX = e.clientX;
        $("table tr td:nth-of-type(" + idx + ")").width(width);
      });
      $(document).mouseup(function() {
        $(document).unbind("mousemove");
      });
    });

  });

});
table.scroll {
  /* width: 100%; */
  /* Optional */
  /* border-collapse: collapse; */
  border-spacing: 0;
  border: 2px solid black;
}
table.scroll tbody,
table.scroll thead {
  display: block;
}
thead tr th {
  height: 30px;
  line-height: 30px;
  /* text-align: left; */
}
table.scroll tbody {
  height: 100px;
  overflow-y: auto;
  overflow-x: hidden;
}
tbody {
  border-top: 2px solid black;
}
tbody td,
thead th {
  /* width: 20%; */
  /* Optional */
  border-right: 1px solid black;
  /* white-space: nowrap; */
}
tbody td:last-child,
thead th:last-child {
  border-right: none;
}
.colResizer {
  background-color: red;
  position: relative;
  cursor: e-resize;
}
.colHandle {
  height: 20px;
  width: 20px;
  background-color: transparent;
  position: absolute;
  right: -10px;
  top: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="scroll">
  <thead>
    <tr>
      <th>Head 1</th>
      <th>Head 2</th>
      <th>Head 3</th>
      <th>Head 4</th>
      <th>Head 5</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Content 1</td>
      <td>Content 2</td>
      <td>Content 3</td>
      <td>Content 4</td>
      <td>Content 5</td>
    </tr>
    <tr>
      <td>Content 1</td>
      <td>Lorem ipsum dolor sit amet.</td>
      <td>Content 3</td>
      <td>Content 4</td>
      <td>Content 5</td>
    </tr>
    <tr>
      <td>Content 1</td>
      <td>Content 2</td>
      <td>Content 3</td>
      <td>Content 4</td>
      <td>Content 5</td>
    </tr>
    <tr>
      <td>Content 1</td>
      <td>Content 2</td>
      <td>Content 3</td>
      <td>Content 4</td>
      <td>Content 5</td>
    </tr>
    <tr>
      <td>Content 1</td>
      <td>Content 2</td>
      <td>Content 3</td>
      <td>Content 4</td>
      <td>Content 5</td>
    </tr>
    <tr>
      <td>Content 1</td>
      <td>Content 2</td>
      <td>Content 3</td>
      <td>Content 4</td>
      <td>Content 5</td>
    </tr>
    <tr>
      <td>Content 1</td>
      <td>Content 2</td>
      <td>Content 3</td>
      <td>Content 4</td>
      <td>Content 5</td>
    </tr>
  </tbody>
</table>