Reputation: 53
I want to create a table with hidden contents from the user but is available if they typed the specific items. So, basically, I just want to have a search bar as the only thing displayed.
Here is what I already have, and this is from w3schools:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
box-sizing: border-box;
}
#myInput {
background-image: url('/css/searchicon.png');
background-position: 10px 10px;
background-repeat: no-repeat;
width: 100%;
font-size: 16px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
margin-bottom: 12px;
}
#myTable {
border-collapse: collapse;
width: 100%;
border: 1px solid #ddd;
font-size: 18px;
}
#myTable th,
#myTable td {
text-align: left;
padding: 12px;
}
#myTable tr {
border-bottom: 1px solid #ddd;
}
#myTable tr.header,
#myTable tr:hover {
background-color: #f1f1f1;
}
</style>
</head>
<body>
<h2>My Customers</h2>
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Germany</td>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Sweden</td>
</tr>
<tr>
<td>Island Trading</td>
<td>UK</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Germany</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Italy</td>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>
<script>
function myFunction() {
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
</script>
</body>
</html>
And lastly, how would I be able to add a clickable link on an item? I've seen a website with those features and I tried to find the answer on my own but can't. I'm also a beginner and have zero background in coding, although I've learned quite fast these past few weeks. So I would appreciate it if you use will use words I can understand.
If you want to know what I'm gonna do with this is I'm planning to build a free books blog where people can just search their favorite author or book title and it will appear on the search bar if it's available. Thanks a lot!
Upvotes: 4
Views: 688
Reputation: 25634
Here is how I would do it. I tried adding as many comments as I could to explain why I did some things. There are some in the HTML, the CSS, and the JS code. Feel free to ask any question.
// When the DOM (HTML structure) is ready
document.addEventListener("DOMContentLoaded", function() {
// First, we can create references to DOM elements on page start,
// which we'll reuse instead of looking them up every time we perform a search.
// As a convention, I like variables holding DOM elements to start with $,
// so that I know what I'm dealing with in the blink of an eye 👀
var $input = document.getElementById("myInput"),
$table = document.getElementById("myTable"),
// Only select the <tr>s inside the <tbody> (double $ -> multiple elements)
$$tr = $table.querySelectorAll("tbody tr");
// Add the normalized name as a property to each tr, so that you don't have
// to compute that every time when performing a search
for (var i = 0; i < $$tr.length; i++) {
$$tr[i].normalizedValue = normalizeStr( $$tr[i].querySelector("td").innerText );
}
// When typing or pasting text, perform a search
$input.addEventListener("input", performSearch);
function performSearch() {
var filter = normalizeStr(this.value);
for (var i = 0; i < $$tr.length; i++) {
var isMatch = $$tr[i].normalizedValue.includes(filter);
// Toggle a 'visible' class
$$tr[i].classList[isMatch ? "add" : "remove"]("visible");
}
}
// Creating a reusable function will allow us to make
// changes to it only in one place 👍
function normalizeStr(str) {
return str.toUpperCase().trim();
}
});
/* ... untouched CSS ... */ *{box-sizing:border-box}#myInput{background-image:url(/css/searchicon.png);background-position:10px 10px;background-repeat:no-repeat;width:100%;font-size:16px;padding:12px 20px 12px 40px;border:1px solid #ddd;margin-bottom:12px}#myTable{border-collapse:collapse;width:100%;border:1px solid #ddd;font-size:18px}#myTable td,#myTable th{text-align:left;padding:12px}#myTable tr{border-bottom:1px solid #ddd}
#myTable thead tr, /* notice the use of thead */
#myTable tr:hover {
background-color: #f1f1f1;
}
#myTable tbody tr {
display: none; /* Hide rows by default */
}
#myTable tbody tr.visible {
display: table-row; /* Show them when they match */
}
<h2>My Customers</h2>
<!-- Try not using `on...=""` attributes. Separating HTML and JS is better practice -->
<input type="text" id="myInput" placeholder="Search for names" title="Type in a name" />
<table id="myTable">
<!-- Use <thead> and <tbody> to separate data from headers -->
<thead>
<tr>
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
</thead>
<tbody>
<tr> <td><a href="http://example.com/">Alfreds Futterkiste</a></td> <td>Germany</td> </tr>
<tr> <td><a href="http://example.com/">Berglunds snabbkop</a></td> <td>Sweden</td> </tr>
<tr> <td><a href="http://example.com/">Island Trading</a></td> <td>UK</td> </tr>
<tr> <td><a href="http://example.com/">Koniglich Essen</a></td> <td>Germany</td> </tr>
<tr> <td><a href="http://example.com/">Laughing Bacchus Winecellars</a></td> <td>Canada</td> </tr>
<tr> <td><a href="http://example.com/">Magazzini Alimentari Riuniti</a></td> <td>Italy</td> </tr>
<tr> <td><a href="http://example.com/">North/South</a></td> <td>UK</td> </tr>
<tr> <td><a href="http://example.com/">Paris specialites</a></td> <td>France</td> </tr>
</tbody>
</table>
Upvotes: 4
Reputation: 14844
You were almost there. Just add in the css
the property display: none
on your rows to hide them. You can then reappear them in javascript using the diplay: table-row
property:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
box-sizing: border-box;
}
#myInput {
background-image: url('/css/searchicon.png');
background-position: 10px 10px;
background-repeat: no-repeat;
width: 100%;
font-size: 16px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
margin-bottom: 12px;
}
#myTable {
border-collapse: collapse;
width: 100%;
border: 1px solid #ddd;
font-size: 18px;
}
#myTable th,
#myTable td {
text-align: left;
padding: 12px;
}
#myTable tr:not(.header) {
display: none; /* <-- Hide all items (but not header) on init */
}
#myTable tr {
border-bottom: 1px solid #ddd;
}
#myTable tr.header,
#myTable tr:hover {
background-color: #f1f1f1;
}
</style>
</head>
<body>
<h2>My Customers</h2>
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Germany</td>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Sweden</td>
</tr>
<tr>
<td>Island Trading</td>
<td>UK</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Germany</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Italy</td>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>
<script>
function myFunction() {
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "table-row"; // <-- Show matching items
} else {
tr[i].style.display = "none";
}
}
}
}
</script>
</body>
</html>
Upvotes: 3