Freeze first row and first column of table - javascript

I am trying to freeze/lock the first row and the first column of a table.
I have tried giving thead position: absolute; or position: fixed; but it looks strange.
I have followed some answers but I am still confused how to make it.
My HTML / CSS Code :
th {
font-size: 80%;
text-align: center;
}
td {
font-size : 65%;
white-space: pre;
text-align: center;
}
.inner {
overflow-x: scroll;
overflow-y: scroll;
width: 300px;
height: 100px;
}
input {
font-size : 65%;
}
<body>
<div class="inner">
<form method="POST" action="dashboard">
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Tanggal</th>
<th>Judul Pekerjaan</th>
<th>Deskripsi</th>
<th>Level</th>
<th>Category</th>
<th>Severity</th>
</tr>
</thead>
</form>
<tbody>
<tr>
<td>1</td>
<td>1 May 2017</td>
<td>Satu</td>
<td>Satu</td>
</tr>
<tr>
<td>2</td>
<td>2 May 2017</td>
<td>Dua</td>
<td>Dua</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
</tbody>
</table>
</div>
</body>

Freeze First Row
Freezing the first row can be done with CSS by setting the table body to overflow: auto, and giving a fixed width to the table cells. (See example 1)
Freeze First Row & First Column
However, to get this behavior for both first row and first column, you need to separate the first row, first column, and first cell from the table, and then continuously set the position of these elements based on the scrolled position of the table body, upon a scroll event. (See example 2)
Example 1: (Freeze first row only)
table thead tr {
display: block;
}
table th, table td {
width: 80px;
}
table tbody {
display: block;
height: 90px;
overflow: auto;
}
th {
text-align: center;
}
td {
text-align: center;
white-space: pre;
}
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Tanggal</th>
<th>Judul Pekerjaan</th>
<th>Deskripsi</th>
<th>Level</th>
<th>Category</th>
<th>Severity</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1 May 2017</td>
<td>Satu</td>
<td>Satu</td>
</tr>
<tr>
<td>2</td>
<td>2 May 2017</td>
<td>Dua</td>
<td>Dua</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
<tr>
<td>2</td>
<td>2 May 2017</td>
<td>Dua</td>
<td>Dua</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
</tbody>
</table>
Example 2: (Freeze first row and first column)
$(document).ready(function() {
$('tbody').scroll(function(e) {
$('thead').css("left", -$("tbody").scrollLeft());
$('thead th:nth-child(1)').css("left", $("tbody").scrollLeft()-5);
$('tbody td:nth-child(1)').css("left", $("tbody").scrollLeft()-5);
});
});
body {
margin: 0;
}
th, td {
text-align: center;
background-color: white
}
table {
position: relative;
width: 400px;
overflow: hidden;
}
thead {
position: relative;
display: block;
width: 400px;
overflow: visible;
}
thead th {
min-width: 80px;
height: 40px;
}
thead th:nth-child(1) {
position: relative;
display: block;
height: 40px;
padding-top: 20px;
}
tbody {
position: relative;
display: block;
width: 400px;
height: 90px;
overflow: scroll;
}
tbody td {
min-width: 80px;
}
tbody tr td:nth-child(1) {
position: relative;
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Tanggal</th>
<th>Judul Pekerjaan</th>
<th>Deskripsi</th>
<th>Level</th>
<th>Category</th>
<th>Severity</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1 May 2017</td>
<td>Satu</td>
<td>Satu</td>
<td>5</td>
<td>Lorem</td>
<td>Ipsum</td>
</tr>
<tr>
<td>2</td>
<td>2 May 2017</td>
<td>Dua</td>
<td>Dua</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
<tr>
<td>2</td>
<td>2 May 2017</td>
<td>Dua</td>
<td>Dua</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
<tr>
<td>3</td>
<td>3 May 2017</td>
<td>Tiga</td>
<td>Tiga</td>
</tr>
</tbody>
</table>

If anyone struggles with such problem here is a solution for modern browsers without using jQuery or even JS - just pure HTML and CSS.
The trick is to set table to relative position and first row and/or column cells to sticky position. I added explicitly background color and z-index values to have this overlapping feeling.
.wrapper {
overflow: auto;
height: 100px;
width: 200px;
}
table {
position: relative;
border-collapse: separate;
border-spacing: 0;
}
table th,
table td {
width: 50px;
padding: 5px;
background-color: white;
}
table tbody {
height: 90px;
}
table th {
text-align: center;
position: sticky;
top: 0;
z-index: 2;
}
table th:nth-child(1) {
left: 0;
z-index: 3;
}
table td {
text-align: center;
white-space: pre;
}
table tbody tr td:nth-child(1) {
position: sticky;
left: 0;
z-index: 1;
}
<div class="wrapper">
<table class="table table-bordered">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Age</th>
<th>Country</th>
<th>Hobbies</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>George</td>
<td>43</td>
<td>New Zealand</td>
</tr>
<tr>
<td>2</td>
<td>Ann</td>
<td>25</td>
<td>Great Britain</td>
</tr>
<tr>
<td>3</td>
<td>Alexander</td>
<td>41</td>
<td>Spain</td>
</tr>
<tr>
<td>4</td>
<td>Wasilij</td>
<td>63</td>
<td>Ukraine</td>
</tr>
<tr>
<td>1</td>
<td>George</td>
<td>43</td>
<td>New Zealand</td>
</tr>
<tr>
<td>1</td>
<td>George</td>
<td>43</td>
<td>New Zealand</td>
</tr>
<tr>
<td>1</td>
<td>George</td>
<td>43</td>
<td>New Zealand</td>
</tr>
</tbody>
</table>
</div>

I resoved this issue from myself with my colleague together yesterday. The adapted CSS is:
.pcvBody {
overflow-x: auto;
width: calc(100vw - 110px);
}
/* CSS START for freezing table column*/
#prodTable {
position: relative;
overflow: hidden;
}
#prodTable thead {
position: relative;
display: block;
overflow: visible;
}
#prodTable thead th {
min-width: 150px;
width: 1000px;
}
#prodTable thead th:nth-child(1), #prodTable thead th:nth-child(2) {
position: relative;
/*display: block;*/
max-width: 150px;
width: 50px;
border-left: 1px solid #ededed;
}
#prodTable tbody {
position: relative;
display: block;
}
#prodTable tbody td {
min-width: 150px;
width: 1000px;
}
#prodTable tbody input {
max-width: 120px;
}
#prodTable tbody tr td:nth-child(1), #prodTable tbody tr td:nth-child(2) {
position: relative;
/*display: block;*/
background-color: white;
min-height: 20px;
max-width: 150px;
width: 50px;
border-left: 1px solid #ededed;
}
/* CSS END for freezing table column*/
And the adjusted scroll event is:
$('#pcvBody').scroll(function(e) {
var scrollLeft = $("#pcvBody").scrollLeft();
//$('#prodTable thead').css("left", -tbodyScrollLeft);
//$('#prodTable thead th:nth-child(1)').css("left", tbodyScrollLeft - 5);
//$('#prodTable tbody td:nth-child(1)').css("left", tbodyScrollLeft - 5);
$('#prodTable thead th:nth-child(1)').css("left", scrollLeft);
$('#prodTable tbody td:nth-child(1)').css("left", scrollLeft);
$('#prodTable thead th:nth-child(2)').css("left", scrollLeft);
$('#prodTable tbody td:nth-child(2)').css("left", scrollLeft);
});
And in addition, I added a 'div' to wrap the table.

Related

How to Fix the TD elements of first column of the table body while the rows are scrolling?

The title is not clear, I know. Let me explain what I mean:
First column has td elements which have varying rowspans. What I want is to keep the td text in first column 'fixed' at the top while scrolling down.
But only as long as the rest of the td elements in the remaining columns are in scope.
Once all the rows (which the first column cell is spanning) is out of table view, the td element should scroll out of the view and the next td should now start fixing.
After Scrolling a bit:
And after All the animal rows are scrolled out, the fixed 'Animal' td would also go up and then 'Cars' would be fixed and then Hats would be fixed like this:
I got it working by setting
vertical-align: top; for the element
and created a div under the td element which contains the actual value for the cell
then applied position: sticky; top:0; z-index: 1; to the div.
Working fiddle: https://jsfiddle.net/ankitkraken/yw0jhzpu/1/
HTML:
<td class="td-class-name" rowspan="3">
<div class="level-1">
"Cars"
</div>
</td>
CSS:
.td-class-names{
vertical-align: top;
}
.level-1{
position: sticky ;
top: 80px;
z-index: -1;
}
I had to use top: 80px;, top:0; was putting the td contents BEHIND the sticky table header.
You can acheive this result with the sticky positioning:
thead tr:first-of-type {
position: sticky;
top: 0px;
z-index: 10;
}
thead tr:first-of-type th {
background: yellow;
}
th {
border: 1px solid;
padding: 6px;
}
td {
border: 1px solid;
padding: 6px;
}
th[rowspan]>.box {
vertical-align: top;
position: sticky;
top: 34px;
}
th[rowspan][data-order='first'] {
background: orange;
}
th[rowspan][data-order='second'] {
background: green;
}
th[rowspan][data-order='third'] {
background: indianred;
}
th[rowspan][data-order='fourth'] {
background: lightblue;
}
.main-container {
position: relative;
}
.table-container {
position: static;
max-height: 180px;
max-width: 350px;
;
overflow-y: scroll;
}
.fake {
width: 100%;
height: 100px;
}
<div class="main-container">
<div class='table-container'>
<table>
<thead>
<tr>
<th>CATEGORY</th>
<th>TYPE</th>
<th>NAME</th>
</tr>
</thead>
<tbody>
<tr>
<th data-order='first' rowspan='5'>
<div class='box'>Animals</div>
</th>
<td>Dog</td>
<td>Bob</td>
</tr>
<tr>
<td>Dog</td>
<td>Flash</td>
</tr>
<tr>
<td>Cat</td>
<td>Mimi</td>
</tr>
<tr>
<td>Dog</td>
<td>Casper</td>
</tr>
<tr>
<td>Horse</td>
<td>Wind Lady</td>
</tr>
<tr>
<th data-order='second' rowspan='5'>
<div class='box'>Cars</div>
</th>
<td>Chrysler</td>
<td>Ann</td>
</tr>
<tr>
<td>Dodge</td>
<td>Christine</td>
</tr>
<tr>
<td>Ford</td>
<td>Foo</td>
</tr>
<tr>
<td>Ferrari</td>
<td>Dandy</td>
</tr>
<tr>
<td>Mercedes</td>
<td>A200</td>
</tr>
<tr>
<th data-order='third' rowspan='5'>
<div class='box'>Food</div>
</th>
<td>Apple</td>
<td>George</td>
</tr>
<tr>
<td>Banana</td>
<td>Rocco</td>
</tr>
<tr>
<td>Strawberry</td>
<td>Liza</td>
</tr>
<tr>
<td>Ananas</td>
<td>Ted</td>
</tr>
<tr>
<td>Avocado</td>
<td>Gary</td>
</tr>
<tr>
<th data-order='fourth' rowspan='5'>
<div class='box'>Phones</div>
</th>
<td>Iphone XXI</td>
<td>ObiWan</td>
</tr>
<tr>
<td>Nokia 8110</td>
<td>Neo</td>
</tr>
<tr>
<td>Ericsson</td>
<td>Dr. Who</td>
</tr>
<tr>
<td>Huawei Mate 40</td>
<td>Dead or Alive</td>
</tr>
<tr>
<td>Xiaomi</td>
<td>Ping</td>
</tr>
</tbody>
</table>
<div class='fake'>
</div>
</div>
</div>
Sticky positioning is not always straightforward, expecially when dealing with overflow properties and display: table. Here are some useful resources about these topics:
Position: stuck; — and a way to fix it
CSS Position Sticky - How It Really Works!
Creating sliding effects using sticky positioning
Position Sticky on <td> with colspan?

How to select items using a input checkbox?

This is my code snippet, I want to display the difference of two selected columns and create a new table with columns selected and difference along as a column. I am not getting how can I select table columns with the help of checkbox (basically bind the checkbox with table columns). I cant find anything on Stack Overflow or any other site for the reference.
Edit: I have added the JS code for getting the column data corresponding to that particular header, right now I am hard coding it to header "Three". How can I pick the particular column data bind to the input checkbox clicked?
columnTh = $("table th:contains('Three')");
columnIndex = columnTh.index() + 1;
let arr = [];
alert(columnIndex)
arr = $('table tr td:nth-child(' + columnIndex + ')').text()
alert(arr)
table {
border: 1px solid white;
text-align: center;
padding: 6px;
background: #e1edf9;
}
td {
border: 1px solid white;
text-align: center;
padding: 6px;
}
td:first-child,
tr:first-child {
background-color: #003a6a !important;
color: white !important;
}
.table-scroll {
position: relative;
width: 100%;
z-index: 1;
margin: auto;
overflow: auto;
}
.table-scroll table {
width: 100%;
min-width: 1280px;
margin: auto;
border-collapse: separate;
border-spacing: 0;
}
.table-wrap {
position: relative;
}
.table-scroll tr:first-child {
background: #333;
color: #fff;
position: -webkit-sticky;
position: sticky;
top: 0;
}
td:first-child {
position: -webkit-sticky;
position: sticky;
left: 0;
z-index: 2;
background: #ccc;
}
.table-scroll tfoot tr {
position: -webkit-sticky;
position: sticky;
bottom: 0;
background: #666;
color: #fff;
z-index: 4;
}
tr:first-child {
z-index: 5;
}
#media screen and (max-width: 500px) {
td:first-child {
position: -webkit-sticky;
position: sticky;
left: 0;
z-index: 2;
background: #ccc;
max-width: 140px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="table-scroll" class="table-scroll">
<table id="main-table" class="main-table">
<tbody>
<tr>
<th>One</th>
<th>Two <input type="checkbox" id="c2" value="on" name="cb2"/></th>
<th>Three<input type="checkbox" id="c3" value="on" name="cb3"/></th>
<th>Four<input type="checkbox" id="c4" value="on" name="cb4"/></th>
<th>Five<input type="checkbox" id="c5" value="on" name="cb5"/></th>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>21</td>
<td>2</td>
<td>93</td>
<td>74</td>
<td>85</td>
</tr>
<tr>
<td>21</td>
<td>32</td>
<td>93</td>
<td>24</td>
<td>15</td>
</tr>
<tr>
<td>91</td>
<td>72</td>
<td>13</td>
<td>14</td>
<td>85</td>
</tr>
<tr>
<td>411</td>
<td>422</td>
<td>423</td>
<td>144</td>
<td>145</td>
</tr>
<tr>
<td>151</td>
<td>522</td>
<td>93</td>
<td>54</td>
<td>515</td>
</tr>
<tr>
<td>610</td>
<td>621</td>
<td>363</td>
<td>464</td>
<td>65</td>
</tr>
<tr>
<td>21</td>
<td>22</td>
<td>13</td>
<td>41</td>
<td>5</td>
</tr>
<tr>
<td>11</td>
<td>120</td>
<td>143</td>
<td>214</td>
<td>5</td>
</tr>
<tr>
<td>21</td>
<td>22</td>
<td>23</td>
<td>24</td>
<td>25</td>
</tr>
<tr>
<td>31</td>
<td>32</td>
<td>33</td>
<td>34</td>
<td>35</td>
</tr>
<tr>
<td>41</td>
<td>42</td>
<td>43</td>
<td>44</td>
<td>45</td>
</tr>
<tr>
<td>51</td>
<td>52</td>
<td>53</td>
<td>54</td>
<td>55</td>
</tr>
<tr>
<td>61</td>
<td>62</td>
<td>63</td>
<td>64</td>
<td>65</td>
</tr>
</tbody>
</table>
</div>
I don't know how you want to display the difference, but this might get you started:
const table = document.getElementById("main-table"),
checkboxes = table.querySelectorAll('th > input[type="checkbox"]');
let columns = {};
for(let i = 0; i < checkboxes.length; i++)
{
checkboxes[i].addEventListener("input", onInput);
}
function onInput(e)
{
const input = e.target,
column = input.parentNode.cellIndex,
tds = table.querySelectorAll('td:nth-child(' + (column + 1) + ')');
if (input.checked)
{
let list = [];
for(let i = 0; i < tds.length; i++)
{
list[list.length] = tds[i].textContent;
}
columns[column] = list;
}
else
{
delete columns[column];
}
if (Object.keys(columns).length > 1)
showDifference();
else
table.classList.remove("result");
}
function showDifference()
{
table.classList.add("result");
let cells = table.getElementsByClassName("result"),
trs = table.querySelectorAll("tr");
if (!cells.length)
{
cells = [];
for(let i = 0, cell; i < trs.length; i++)
{
cell = document.createElement(i ? "td" : "th");
if (!i)
cell.textContent = "Results";
cell.className = "result";
cells[cells.length] = cell;
trs[i].appendChild(cell);
}
}
let dif = [];
for(let r in columns)
{
for(let i = 0; i < columns[r].length; i++)
{
if (dif[i] === undefined)
dif[i] = [];
dif[i][dif[i].length] = columns[r][i];
}
}
for(let i = 0; i < dif.length; i++)
{
cells[i+1].textContent = dif[i];
}
}
table {
border: 1px solid white;
text-align: center;
padding: 6px;
background: #e1edf9;
}
td {
border: 1px solid white;
text-align: center;
padding: 6px;
}
td:first-child,
tr:first-child {
background-color: #003a6a !important;
color: white !important;
}
.table-scroll {
position: relative;
width: 100%;
z-index: 1;
margin: auto;
overflow: auto;
}
.table-scroll table {
width: 100%;
min-width: 1280px;
margin: auto;
border-collapse: separate;
border-spacing: 0;
}
.table-wrap {
position: relative;
}
.table-scroll tr:first-child {
background: #333;
color: #fff;
position: -webkit-sticky;
position: sticky;
top: 0;
}
td:first-child {
position: -webkit-sticky;
position: sticky;
left: 0;
z-index: 2;
background: #ccc;
}
.table-scroll tfoot tr {
position: -webkit-sticky;
position: sticky;
bottom: 0;
background: #666;
color: #fff;
z-index: 4;
}
tr:first-child {
z-index: 5;
}
#media screen and (max-width: 500px) {
td:first-child {
position: -webkit-sticky;
position: sticky;
left: 0;
z-index: 2;
background: #ccc;
max-width: 140px;
}
}
.main-table:not(.result) th.result,
.main-table:not(.result) td.result
{
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="table-scroll" class="table-scroll">
<table id="main-table" class="main-table">
<tbody>
<tr>
<th>One</th>
<th>Two <input type="checkbox" id="c2" value="on" name="cb2"/></th>
<th>Three<input type="checkbox" id="c3" value="on" name="cb3"/></th>
<th>Four<input type="checkbox" id="c4" value="on" name="cb4"/></th>
<th>Five<input type="checkbox" id="c5" value="on" name="cb5"/></th>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>21</td>
<td>2</td>
<td>93</td>
<td>74</td>
<td>85</td>
</tr>
<tr>
<td>21</td>
<td>32</td>
<td>93</td>
<td>24</td>
<td>15</td>
</tr>
<tr>
<td>91</td>
<td>72</td>
<td>13</td>
<td>14</td>
<td>85</td>
</tr>
<tr>
<td>411</td>
<td>422</td>
<td>423</td>
<td>144</td>
<td>145</td>
</tr>
<tr>
<td>151</td>
<td>522</td>
<td>93</td>
<td>54</td>
<td>515</td>
</tr>
<tr>
<td>610</td>
<td>621</td>
<td>363</td>
<td>464</td>
<td>65</td>
</tr>
<tr>
<td>21</td>
<td>22</td>
<td>13</td>
<td>41</td>
<td>5</td>
</tr>
<tr>
<td>11</td>
<td>120</td>
<td>143</td>
<td>214</td>
<td>5</td>
</tr>
<tr>
<td>21</td>
<td>22</td>
<td>23</td>
<td>24</td>
<td>25</td>
</tr>
<tr>
<td>31</td>
<td>32</td>
<td>33</td>
<td>34</td>
<td>35</td>
</tr>
<tr>
<td>41</td>
<td>42</td>
<td>43</td>
<td>44</td>
<td>45</td>
</tr>
<tr>
<td>51</td>
<td>52</td>
<td>53</td>
<td>54</td>
<td>55</td>
</tr>
<tr>
<td>61</td>
<td>62</td>
<td>63</td>
<td>64</td>
<td>65</td>
</tr>
</tbody>
</table>
</div>

Align the columns of thead with tbody

There is a table without any settings for <thead> and <tbody>. And it looks like this:
I had to make the table scrollable, so in this case I added to <tbody> this styling:
display: block;
height: 475px;
overflow: scroll;
Now, <tbody> has a height of 475px and it's scrollable. This problem was solved!
But now <thead> doesn't look right:
To solve this problem, I added to <thead>:
display: table;
Now it looks better:
But still, the column headers are not aligned to the columns.
How can be this solved and make the table looks like it was looking before adding the scrolling part?
You can make this basically by setting thead and tbody display as block, and setting a fixed width to both th and td tags.
table {
background: steelblue
}
thead, tbody {
display: block;
}
tbody {
overflow-y: scroll;
height: 100px;
}
thead th:nth-child(1), tbody td:nth-child(1) {
background: pink;
width: 90px;
word-break: break-all;
}
thead th:nth-child(2), tbody td:nth-child(2) {
background: olive;
width: 140px;
word-break: break-all;
}
thead th:nth-child(3), tbody td:nth-child(3) {
background: tomato;
width: 80px;
word-break: break-all;
}
<table>
<thead>
<tr>
<th>Make Payment</th>
<th>Order Number</th>
<th>Order Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>V</td>
<td>9598959</td>
<td>2020-05-12</td>
</tr>
<tr>
<td>Inserting a long text here just to show it breaks</td>
<td>9598959</td>
<td>2020-05-12</td>
</tr>
<tr>
<td>V</td>
<td>9598959</td>
<td>2020-05-12</td>
</tr>
<tr>
<td>V</td>
<td>9598959</td>
<td>2020-05-12</td>
</tr>
<tr>
<td>V</td>
<td>9598959</td>
<td>2020-05-12</td>
</tr>
<tr>
<td>V</td>
<td>9598959</td>
<td>2020-05-12</td>
</tr>
<tr>
<td>V</td>
<td>9598959</td>
<td>2020-05-12</td>
</tr>
</tbody>
</table

jqGrid frozen header

We use latest version of free-jqgrid.
We want to make for all our grids fixed (frozen) header: verticall scrollbar insided the grid, which scrolls only the content.
As I know, this can be achieved using fixed grid's height, but it would be great to have the height fit to user's screen height. (May be we should change the size on page load somehow?)
What is the best way to implement this?
Example: https://jsfiddle.net/qrxkuvfz/1/
Setting width: 400 does bad job.
I just want the scroll to be inside the grid. And height - max available.
If I correctly understand your requirements, then you need just add `` option to jqGrid. For example, the modified demo https://jsfiddle.net/OlegKi/qrxkuvfz/2/ uses
rowNum: 15,
maxHeight: 330,
The maxHeight is large enough to display all 15 rows specified in rowNum, but if the user increase .
Alternatively you can use onPaging callback (see the wiki article), where you use setGridHeight method to set height option of jqGrid to some numeric value or to "auto" depend on the newRowNum and currentRowNum properties of the options parameter.
Basically, you can use your css to fix your headers (frozen), and use a bit of javascript/jquery to assign height to the tbody so that the table fits on to the screen.
Also add an overflow property to enable scrollbar in your css after the specific height.
Refer code:
$("tbody").height($(window).innerHeight() + "px");
table {
position: relative;
width: 700px;
background-color: #aaa;
overflow: hidden;
border-collapse: collapse;
}
/*thead*/
thead {
position: relative;
display: block;
/*seperates the header from the body allowing it to be positioned*/
width: 700px;
overflow: visible;
}
thead th {
background-color: #99a;
min-width: 120px;
height: 36px;
min-height: 36px;
border: 1px solid #222;
}
thead th:nth-child(1) {
/*first cell in the header*/
position: relative;
display: block;
background-color: #88b;
}
/*tbody*/
tbody {
display: block;
width: 700px;
overflow-y: auto;
}
tbody td {
background-color: #bbc;
min-width: 120px;
border: 1px solid #222;
height: 36px;
min-height: 36px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<table>
<thead>
<tr>
<th>Name</th>
<th>Town</th>
<th>County</th>
<th>Age</th>
<th>Profession</th>
<th>Anual Income</th>
<th>Matital Status</th>
<th>Children</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Smith</td>
<td>Macelsfield</td>
<td>Cheshire</td>
<td>52</td>
<td>Brewer</td>
<td>£47,000</td>
<td>Married</td>
<td>2</td>
</tr>
<tr>
<td>Jenny Jones</td>
<td>Threlkeld</td>
<td>Cumbria</td>
<td>34</td>
<td>Shepherdess</td>
<td>£28,000</td>
<td>Single</td>
<td>0</td>
</tr>
<tr>
<td>Peter Frampton</td>
<td>Avebury</td>
<td>Wiltshire</td>
<td>57</td>
<td>Musician</td>
<td>£124,000</td>
<td>Married</td>
<td>4</td>
</tr>
<tr>
<td>Simon King</td>
<td>Malvern</td>
<td>Worchestershire</td>
<td>48</td>
<td>Naturalist</td>
<td>£65,000</td>
<td>Married</td>
<td>2</td>
</tr>
<tr>
<td>Lucy Diamond</td>
<td>St Albans</td>
<td>Hertfordshire</td>
<td>67</td>
<td>Pharmasist</td>
<td>Retired</td>
<td>Married</td>
<td>3</td>
</tr>
<tr>
<td>Austin Stevenson</td>
<td>Edinburgh</td>
<td>Lothian</td>
<td>36</td>
<td>Vigilante</td>
<td>£86,000</td>
<td>Single</td>
<td>Unknown</td>
</tr>
<tr>
<td>Wilma Rubble</td>
<td>Bedford</td>
<td>Bedfordshire</td>
<td>43</td>
<td>Housewife</td>
<td>N/A</td>
<td>Married</td>
<td>1</td>
</tr>
<tr>
<td>Kat Dibble</td>
<td>Manhattan</td>
<td>New York</td>
<td>55</td>
<td>Policewoman</td>
<td>$36,000</td>
<td>Single</td>
<td>1</td>
</tr>
<tr>
<td>Henry Bolingbroke</td>
<td>Bolingbroke</td>
<td>Lincolnshire</td>
<td>45</td>
<td>Landowner</td>
<td>Lots</td>
<td>Married</td>
<td>6</td>
</tr>
<tr>
<td>Alan Brisingamen</td>
<td>Alderley</td>
<td>Cheshire</td>
<td>352</td>
<td>Arcanist</td>
<td>A pile of gems</td>
<td>Single</td>
<td>0</td>
</tr>
</tbody>
</table>
</body>

Sticky header and footer scrollable main area

I want my page to have a fixed header and footer, which must stay on screen all the time. The lateral panel is on an aside, and the main content inside a section.
Using JavaScript, I managed to keep the aside occupying all the remaining height (window.height - header.height - footer.height). But it only works when the section is not too high. When I resize the window, I can see that the footer is disappearing under the bottom edge of the window, giving room to the section.
I tried many different combinations of overflow-y (inside section, on the div inside it, on both), to no avail. How can I solve it?
I made a jsfiddle example.
function resize() {
var hPage = window.innerHeight;
var hHead = document.getElementById('header').offsetHeight;
var hFoot = document.getElementById('footer').offsetHeight;
document.getElementById('spn').innerHTML = 'Page: ' + hPage + '<BR>Head: ' + hHead + '<BR>Foot: ' + hFoot;
document.getElementById('aside').style.height = (hPage - hHead - hFoot) + 'px';
}
html,
body {
height: 100%;
margin: 0;
overflow-x: hidden;
overflow-y: hidden;
}
header {
background-color: green;
color: white;
text-align: center;
font-weight: bold;
font-size: 30px;
}
section {
float: right;
width: 80%;
overflow-x: auto;
overflow-y: auto;
}
section div {
padding: 10px;
overflow-x: auto;
overflow-y: auto;
}
aside {
float: left;
background-color: lightgreen;
width: 20%;
}
aside p {
margin-left: 20px;
}
footer {
background-color: green;
color: white;
text-align: center;
clear: both;
}
table {
border-collapse: collapse;
}
th {
border: 1px solid black;
text-align: center;
font-weight: bold;
}
td {
border: 1px solid black;
text-align: center;
}
<body onload='resize()' onresize='resize()'>
<header id='header'>Test 0.1</header>
<aside id='aside'>
<p>Menu 1</p>
<p>Menu 2</p>
<p>Menu 3</p>
<p>Menu 4</p>
<p><span id='spn'>n</span>
</p>
</aside>
<section>
<div id='divMain'>
<table>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</table>
</div>
</section>
<footer id='footer'>Address,
<br>phone,
<br>etc.
<br>
<br>Address,
<br>phone,
<br>etc.</footer>
</body>
Try the flexbox approach, no javascript is needed. Added a <main> element wraps the <aside> and <section>.
jsFiddle
html,
body {
height: 100%;
}
body {
margin: 0;
display: flex;
flex-direction: column;
}
header {
background-color: green;
color: white;
text-align: center;
font-weight: bold;
font-size: 30px;
}
main {
flex: 1;
display: flex;
min-height: 0;
}
aside {
background-color: lightgreen;
width: 20%;
overflow: auto;
}
aside p {
margin-left: 20px;
}
section {
width: 80%;
overflow: auto;
}
section div {
padding: 10px;
}
footer {
background-color: green;
color: white;
text-align: center;
}
table {
border-collapse: collapse;
}
th {
border: 1px solid black;
text-align: center;
font-weight: bold;
}
td {
border: 1px solid black;
text-align: center;
}
<header id='header'>
Test 0.1
</header>
<main>
<aside id='aside'>
<p>Menu 1</p>
<p>Menu 2</p>
<p>Menu 3</p>
<p>Menu 4</p>
<p><span id='spn'>n</span>
</p>
</aside>
<section>
<div id='divMain'>
<table>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</table>
</div>
</section>
</main>
<footer id='footer'>
Address,
<br>phone,
<br>etc.
<br>
<br>Address,
<br>phone,
<br>etc.
<br>
</footer>
If you want to make the header and footer to have a fixed position then you should use position:fixed attribute.
Here is the fiddle
You can apply position:fixed to the footer & also to show the table if it's height overflows , you need to add scroll option.
Here is a css which may help you
#footer{
position:fixed;
bottom:0;
width:100%
}
#divMain{
overflow-y:auto; // scrollbar will only appear when require
height:500px; // you can adjust this height
}
DEMO

Categories

Resources