Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
body{
overflow: hidden;
font-family: Verdana, Geneva, sans-serif;
text-align: center;
margin: 4px;
}
table.gridtable{
width: 100%;
font-size:12px;
color:#333333;
border-color: #D7D7D7;
border-collapse: collapse;
}
table.gridtable th {
border-width: 0.5px;
height: 32px;
border-style: solid;
border-color: #D7D7D7;
background-color: #D3EFFF;
}
table.gridtable td {
border-width: 0.5px;
height: 32px;
border-style: solid;
border-color: #D7D7D7;
background-color: #ffffff;
}
table.gridtable td:hover{
background-color: #f1f1f1;
}
.footer{
height: 48px;
left: 50%;
transform: translateX(-50%);
position: absolute;
bottom: 4px;
user-select: none;
}
a{
color: black;
padding: 8px;
text-decoration: none;
transition: background-color .3s;
}
/* Add a grey background color on mouse-over */
a:hover:not(.active) {background-color: #D8E9F2;}
/* search field */
#search{
display: inline-block;
width: 84px;
font-size: 12px;
padding: 8px;
border: 1px solid #ddd;
}
.loader{
position: absolute;
left: 46%;
top: 40%;
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 120px;
height: 120px;
-webkit-animation: spin 2s linear infinite; /* Safari */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you test this on Safari?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I didn't - will remove it for now since it's not necessary to include.

animation: spin 2s linear infinite;
}

/* Safari */
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
153 changes: 153 additions & 0 deletions app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
let firstIndex:number, lastIndex:number; // stores the indices of the first and last rows in the table
let recordCount:number; // stores the number of records in the database
let resizeTimer; // stores time since last window resize

// builds the grid table from the column headers and row data
function buildTable(columns, records) {

// create table
let table = document.createElement("table");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consistently use tabs/spaces for formatting. We set up VSCode for our projects to auto-format our code, so this isn't usually a problem, but if you don't have help from the IDE you have to do it manually. Formatting-war is a real thing and we do all we can to prevent it :)

table.className = "gridtable";
let thead = document.createElement("thead");
let tbody = document.createElement("tbody");
let headRow = document.createElement("tr");

// create column headers
for(const header of columns) {
var th = document.createElement("th");
th.appendChild(document.createTextNode(header));
headRow.appendChild(th);
};
thead.appendChild(headRow);
table.appendChild(thead);

// create rows
records.forEach(function (el) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather use for of loop or old fashioned for loop

let tr = document.createElement("tr");
for (var o in el) {
let td = document.createElement("td");
td.appendChild(document.createTextNode(el[o]))
tr.appendChild(td);
}
tbody.appendChild(tr);
});
table.appendChild(tbody);

// builds footer elements (buttons, search field)
document.getElementById("footer").innerHTML = `<a onclick="goPrevious()">&laquo;</a>
<a onclick="goNext()">&raquo;</a>
<input type="text" id="search" onkeyup="search(event)" placeholder="Enter ID...">`;

document.getElementById("loader").remove();

return table;
}

// filters rows by user input ID
function search(e){
let input = $("#search").val().toString();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't a problem here, but when working in the codebase for our other projects, you will need to use more specific div IDs since they are in a "global namespace" of sorts and could conflict with the naming of existing divs.

let $table = $("tbody tr").toArray();

for(const record of $table){
let td = record.getElementsByTagName("td")[0];
record.style.display="block";
if(td){
let val = td.innerText || td.textContent;
if(val.indexOf(input) > -1){

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't overuse ternary statements but here you could:

record.style.display = val.indexOf(input) === -1 ? "none" : "";

record.style.display = "";
}
else{
record.style.display = "none";
}
}
}

// if record doesn't exist on current page, query database and display results
if(e.which == 13)
{
let end = parseInt(input) + calculateRows();
clearTable();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you always clearTable before you loadPage you can move clearPage inside loadPage

loadPage(parseInt(input), end);
}
}

// load the previous page
function goPrevious(){
let numRows = calculateRows();
if(lastIndex > numRows){
clearTable();
loadPage(firstIndex-numRows, firstIndex-1);
}
}

// load the next page
function goNext(){
if(lastIndex < recordCount-1)
{
clearTable();
loadPage(lastIndex+1, lastIndex+calculateRows());
}
}

// clears the table and footer elements
function clearTable(){
document.getElementById("content").innerHTML="";
document.getElementById("footer").innerHTML="";
}

// loads the columns and rows to be displayed based on start and end row indices
function loadPage(start:number, end:number){

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could make this take only the start index and then you add caclulateRows() inside this method to calc the end index.

firstIndex = start;
lastIndex = end;

// check bounds
if(firstIndex<0) firstIndex = 0;
if(lastIndex>=recordCount) lastIndex = recordCount-1;
if(firstIndex>=recordCount){
firstIndex = recordCount - calculateRows();
}

// create loader
let loader = document.createElement("loader");
document.getElementById("content").appendChild(loader);
loader.innerHTML=`<div class="loader" id="loader"></div>`;

// outter function to fetch column headers from server
$.get("http://localhost:2050/columns", function(columns){

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call will always return the same values, so you can call it once and cache the results, like you did with record count.


// inner function to fetch rows from server and invoke table build function
$.get("http://localhost:2050/records?from="+firstIndex+"&to="+lastIndex, function(rows){
document.getElementById("content").appendChild(buildTable(JSON.parse(columns), JSON.parse(rows)));
});
});
}

// determines the number of rows to display based on the window height
function calculateRows(){
let x = (window.innerHeight - document.getElementById("footer").offsetHeight - document.getElementById("tableHeading").offsetHeight - 64)/36;
return Math.floor(x)-1;
}

window.onload = function () {
// hide browser scroll bar
document.body.style.overflow = "hidden";

// get record count
$.get("http://localhost:2050/recordCount", function(data){

// load the first page
loadPage(0, calculateRows());
recordCount = JSON.parse(data);
});

}

// updates the table display when the window is resized
// debounce function to reduce frequency of queries made
window.onresize = () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function(){

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

clearTable();
loadPage(firstIndex, firstIndex + calculateRows());
}, 250);
}
21 changes: 13 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
<!DOCTYPE html>
<html>
<!DOCTYPE html>

<html lang="en">

<head>
<title>JS Onboard Project</title>
<script type="text/javascript" charset="utf-8" src="third_party/jquery-2.0.3.min.js"></script>
<meta charset="utf-8" />
<title>TEST</title>
<link rel="stylesheet" href="app.css" type="text/css" />
<script src="app.js"></script>
<script src="third_party/jquery-2.0.3.min.js"></script>
</head>

<body>
<p>Hello</p>
<h1 id="tableHeading">Table Heading</h1>
<div id="content"></div>
<div class="footer" id="footer"></div>
</body>

</html>

</html>