<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Table Search</title>
<style>
*,
::after,
::before {
box-sizing: border-box;
}
body {
background-color: rgb(174, 214, 241);
}
.help {
font-size: 1rem;
font-weight: bold;
line-height: 0;
}
.data-table {
top: 383px;
position: sticky;
}
</style>
</head>
<body>
<h1>Search Strain Data</h1>
<p class="help">Please see the <a href="add-your-link-here" target="_blank"><b>help</b></a> for further details.</p>
<form>
<div class="search-block">
<input name="search-input" type="text" id="name" placeholder="taxon name" data-key="taxon" />
<input name="search-input" type="text" id="strain" placeholder="strain" data-key="strain" />
<input name="search-input" type="text" id="accession" placeholder="accession" data-key="accession" />
<input name="search-input" type="text" id="length" placeholder="length" data-key="length" />
<label>
Please Choose a search criteria
<select class="length-dropdown">
<option value="exact value">exact value</option>
<option value="greater than">greater than</option>
<option value="less than">less than</option>
</select>
</label>
<input type="reset" class="reset-btn" value="Reset" title="clear all queries, restore table">
</div>
</form>
<table class="data-table">
<thead>
<th class="name-col-head">taxon name (genus/species)</th>
<th class="strain-col-head">strain</th>
<th class="accession-col-head">accession</th>
<th class="length-col-head">length (bp)</th>
</thead>
<tbody>
</tbody>
</table>
<script>
"use strict";
/*
I will store all the information related to the table then display them dynamically, in this example
I will have 20 objects with five properties each representing 20rows and five columns
*/
const DATA = [
{ taxon: "Alice Johnson", strain: "AB", accession: "XY", length: 450 },
{ taxon: "Bob Smith", strain: "CD", accession: "XY", length: 350 },
{ taxon: "Carol Davis", strain: "EF", accession: "GH", length: 470 },
{ taxon: "David Wilson", strain: "AB", accession: "IJ", length: 460 },
{ taxon: "Eve Martinez", strain: "GH", accession: "KL", length: 300 },
{ taxon: "Frank Brown", strain: "IJ", accession: "MN", length: 510 },
{ taxon: "Grace Lee", strain: "CD", accession: "OP", length: 520 },
{ taxon: "Henry Young", strain: "KL", accession: "QR", length: 480 },
{ taxon: "Ivy White", strain: "EF", accession: "ST", length: 410 },
{ taxon: "Jack Green", strain: "MN", accession: "UV", length: 360 },
{ taxon: "Alice Johnson", strain: "OP", accession: "XY", length: 420 },
{ taxon: "Laura King", strain: "QR", accession: "AB", length: 490 },
{ taxon: "Megan Hall", strain: "ST", accession: "CD", length: 430 },
{ taxon: "Nathan Scott", strain: "UV", accession: "EF", length: 390 },
{ taxon: "Olivia Clark", strain: "WX", accession: "GH", length: 530 },
{ taxon: "Paul Wright", strain: "YZ", accession: "IJ", length: 370 },
{ taxon: "Quincy Turner", strain: "WX", accession: "KL", length: 460 },
{ taxon: "Rachel Baker", strain: "AB", accession: "MN", length: 440 },
{ taxon: "Steven Moore", strain: "CD", accession: "OP", length: 490 },
{ taxon: "Tracy Adams", strain: "EF", accession: "QR", length: 470 },
];
const tableBody = document.querySelector(".data-table > tbody");
const searchInputs = document.getElementsByName("search-input");
const criteriaMenu = document.querySelector('.length-dropdown');
const resetBtn = document.querySelector(".reset-btn");
function generateTableRows(obj) {
const tableRow = document.createElement("tr");
for (const key in obj) {
if (Object.hasOwn(obj, key)) {
const tableCell = document.createElement("td");
tableCell.classList.add(`${ key }-col`);
tableCell.innerText = obj[key];
tableRow.appendChild(tableCell);
}
}
return tableRow;
}
function generateTableBody(dataSet) {
const documentFragment = new DocumentFragment();
const tableRows = dataSet.map(generateTableRows);
tableRows.forEach((row) => {
documentFragment.appendChild(row);
})
tableBody.replaceChildren();
tableBody.appendChild(documentFragment);
}
function filterTable() {
const userInputs = Object.fromEntries(Array.prototype.map.call(searchInputs, (input) => [input.dataset.key, input.value]));
const filteredData = DATA.filter((object) => validateRow(object, userInputs));
generateTableBody(filteredData);
}
function validateRow(object, userInputs) {
for (const property in userInputs) {
if (property === "length") {
if (!validateLength(Number(object[property]), Number(userInputs[property]))) return false
continue;
}
if (!includeWord(object[property], userInputs[property])) return false;
}
return true;
}
function validateLength(lengthValue, userLength) {
if (userLength === 0) return true;
const searchCriteria = criteriaMenu.value;
switch (searchCriteria) {
case ("greater than"): {
return lengthValue > userLength;
}
case ("less than"): {
return lengthValue < userLength;
}
default: {
return lengthValue === userLength;
}
}
}
function resetTable() {
searchInputs.forEach((input) => {
input.value = "";
})
criteriaMenu.value = "exact value";
filterTable();
}
const includeWord = (text, word) => {
const wordRegex = new RegExp(word, "i");
return wordRegex.test(text);
}
window.addEventListener("load", () => {
generateTableBody(DATA);
});
searchInputs.forEach((input) => {
input.addEventListener("keyup", filterTable);
})
criteriaMenu.addEventListener("change", () => {
const lengthInput = document.getElementById("length");
if (lengthInput.value === "") return;
filterTable();
})
resetBtn.addEventListener("click", resetTable);
</script>
</body>
</html>