2

I'm trying to filter this HTML table by writing some text in a search form, which works great but whenever it filters, the elements try to fill the whole width of the table instead of keeping their original element width (25% of the table's width, without counting the spaces between the cells).

function searchFilter () {
   const input = document.getElementById('myInput');
   const filter = input.value.toUpperCase();
   const table = document.getElementById('tablaPiola');
   const articule = table.getElementsByTagName('td');

   for (i = 0; i < articule.length; i++) {
      a = articule[i].getElementsByTagName("a")[0];
      txtValue = a.textContent || a.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
         articule[i].style.display = "";
         } else {
         articule[i].style.display = "none";
         }
   }
}

document.getElementById("filter-btn").addEventListener("click", searchFilter);
body {
background-color: black;
}

table
{border-spacing: 20px;
table-layout: fixed;
width: 600px;
margin: auto;
margin-top: 10px;}

td
{text-align: center;
border-radius: 10px;}

td a
{width: 100%;
display: block;
line-height: 50px;
text-decoration: none;
font-family: "Poppins";
font-weight: 700;
font-size: 12px;
color: white;}

.automatizaciones
{background-image: url("https://via.placeholder.com/100/0000FF/0000FF");
background-size: cover;}

.bpm_a_ms
{background-image: url("https://via.placeholder.com/100/0000FF/0000FF");
background-size: cover;}

.compresion
{background-image: url("https://via.placeholder.com/100/0000FF/0000FF");
background-size: cover;}

.compresion_multibanda
{background-image: url("https://via.placeholder.com/100/0000FF/0000FF");
background-size: cover;}
<input type="text" id="myInput">
<input type="button" id="filter-btn" value="Apply">
<table class="tabla_basico" id="tablaPiola">
   <tr>
      <td class="automatizaciones">
         <div class="overlay_basico"><a href="/">AUTOMATIZACIONES</a></div>
      </td>
      <td class="bpm_a_ms">
         <div class="overlay_intermedio"><a href="/">BPM A MS</a></div>
      </td>
      <td class="compresion">
         <div class="overlay_basico"><a href="compresion.html">COMPRESIÓN</a></div>
      </td>
      <td class="compresion_multibanda">
         <div class="overlay_intermedio"><a href="/">COMPRESIÓN MULTIBANDA</a></div>
       </td>
   </tr>
</table>

This is my webpage

This is how it filters

Andreas
  • 21,535
  • 7
  • 47
  • 56
Sztraji
  • 37
  • 5
  • 3
    Welcome to Stack Overflow! **Nice one** including almost all of the relevant HTML, CSS, and JavaScript! I was able to take what you'd provided and create a runnable version in your question using Stack Snippets (the `[<>]` toolbar button). For next time, [here's how to do one](https://meta.stackoverflow.com/questions/358992/). Again, well done including nearly everything needed, and not too much extra. – T.J. Crowder Mar 08 '20 at 19:00
  • I'm just curious: What language is that? It looks a bit like a couple of languages I'm familiar with, but not quite like any of them. :-) Your location argues for Brazilian Portuguese, but `articule` would be `artigos` if I'm not mistaken. `articule` looks Italian, but it would be `articoli`. And Spanish wouldn't use that form of plural. Clearly a romance language, but... I'm just curious, I love languages. – T.J. Crowder Mar 08 '20 at 19:14
  • I'm from Buenos Aires, Argentina so it's Spanish :) – Sztraji Mar 08 '20 at 19:22
  • I'm using some words in english and some in spanish. Thought "articule" was english for "articulo" (spanish) :P – Sztraji Mar 08 '20 at 19:29
  • 1
    Ah! In English it's "article" and "articles" :-D – T.J. Crowder Mar 09 '20 at 07:25

1 Answers1

2

I originally thought visibility: hidden but you pointed out that that means the ones that are showing aren't on the left anymore.

My only other thought is adding padding cells at the end:

function searchFilter () {
   const input = document.getElementById('myInput');
   const filter = input.value.toUpperCase();
   const table = document.getElementById('tablaPiola');
   // Remove any fillers we added last time
   table.querySelectorAll(".filler").forEach(filler => {
       filler.parentNode.removeChild(filler);
   });
   const articule = table.getElementsByTagName('td');
   // Remember how many are showing at the end
   let showing = 0;

   for (i = 0; i < articule.length; i++) {
      a = articule[i].getElementsByTagName("a")[0];
      txtValue = a.textContent || a.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
         articule[i].style.display = "";
         ++showing; // Remember we're showing this one
      } else {
         articule[i].style.display = "none";
      }
   }
   // Grab the length (since `articule` is a live list
   const max = articule.length;
   // Add blank cells to the end
   while (showing < max) {
      const filler = document.createElement("td");
      filler.className = "filler";
      table.appendChild(filler);
      ++showing;
   }
}

Live Example:

function searchFilter () {
   const input = document.getElementById('myInput');
   const filter = input.value.toUpperCase();
   const table = document.getElementById('tablaPiola');
   // Remove any fillers we added last time
   table.querySelectorAll(".filler").forEach(filler => {
       filler.parentNode.removeChild(filler);
   });
   const articule = table.getElementsByTagName('td');
   // Remember how many are showing at the end
   let showing = 0;
   
   for (i = 0; i < articule.length; i++) {
      a = articule[i].getElementsByTagName("a")[0];
      txtValue = a.textContent || a.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
         articule[i].style.display = "";
         ++showing; // Remember we're showing this one
      } else {
         articule[i].style.display = "none";
      }
   }
   // Grab the length (since `articule` is a live list
   const max = articule.length;
   // Add blank cells to the end
   while (showing < max) {
      const filler = document.createElement("td");
      filler.className = "filler";
      table.appendChild(filler);
      ++showing;
   }
}

document.getElementById("filter-btn").addEventListener("click", searchFilter);
body {
background-color: black;
}

table
{border-spacing: 20px;
table-layout: fixed;
width: 1200px;
margin: auto;
margin-top: 100px;}

td
{text-align: center;
border-radius: 10px;}

td a
{width: 100%;
display: block;
line-height: 150px;
text-decoration: none;
font-family: "Poppins";
font-weight: 700;
font-size: 17.5px;
color: white;}

.automatizaciones
{background-image: url(imagenes/basico/automatizaciones/articulo.jpg);
background-size: cover;}

.bpm_a_ms
{background-image: url(imagenes/intermedio/bpm_a_ms/articulo.jpg);
background-size: cover;}

.compresion
{background-image: url(imagenes/basico/compresion/articulo.jpg);
background-size: cover;}

.compresion_multibanda
{background-image: url(imagenes/intermedio/compresion_multibanda/articulo.jpg);
background-size: cover;}
<input type="text" id="myInput">
<input type="button" id="filter-btn" value="Apply">
<table class="tabla_basico" id="tablaPiola">
   <tr>
      <td class="automatizaciones">
         <div class="overlay_basico"><a href="/">AUTOMATIZACIONES</a></div>
      </td>
      <td class="bpm_a_ms">
         <div class="overlay_intermedio"><a href="/">BPM A MS</a></div>
      </td>
      <td class="compresion">
         <div class="overlay_basico"><a href="compresion.html">COMPRESIÓN</a></div>
      </td>
      <td class="compresion_multibanda">
         <div class="overlay_intermedio"><a href="/">COMPRESIÓN MULTIBANDA</a></div>
       </td>
   </tr>
</table>

Some other notes not directly related to the main problem:

  • That code falls prey to what I call The Horror of Implicit Globals. You never declare i, a, or txtValue so you end up creating global variables when you assign to them. I recommend using strict mode in all code so you get an error when you try to do that.

  • FWIW, I see you're using ES2015+ features (const, for instance), so you could use a for-of loop instead of a for loop. for-of is a bit less typing. But you may need to polyfill iterability on some platforms. My answer here shows how to do that.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • This works fine in terms of filtering but I want them to appear at the start of the table instead of staying in their original table position. – Sztraji Mar 08 '20 at 19:10
  • I'll give all that a look, I've just learnt JavaScript through some courses on codecademy so I'm pretty much a begginer in the subject. Yep, now they remain at 25% so thats cool. – Sztraji Mar 08 '20 at 19:27
  • That last update seems to apply a unique filter in every row, so every element that applies to the condition moves to the first/second/third/fourth of each row (in case there are up to 4 elements in that row appliying to the condition), instead of filling the first row, then the second, etc. – Sztraji Mar 08 '20 at 20:00
  • @Sztraji - I'm afraid I don't know what you mean by that. – T.J. Crowder Mar 09 '20 at 07:25
  • 1
    Solved it, made a whole new
    table/grid instead of an actual so I didn't have to deal with different row tags and it worked great! :) Thanks for the help
    – Sztraji Mar 09 '20 at 16:58