Jak filtrować tabelę danych - budujemy prostą wyszukiwarkę

|
Robert
| komentarze | JavaScript

Załóżmy, że posiadamy tabelę z danymi i chcieli byśmy w niej wyszukiwać informację w czasie rzeczywistym, przychodzi nam na ratunek JavaScript. Język ten (podobno) jest najbardziej niezrozumiałym językiem na świecie, ale nic bardziej mylnego, bo są osoby (w tym ja) które odnajdą się w nim bez problemu. Dziś zrobimy prostą wyszukiwarkę w czystym JS'ie na bazie inputa i danych z tabeli.

Zrobiłem jakiś czas temu skrypt w php który pobiera kompletną listę odcinków pewnego programu rozrywkowego z player.pl, a następnie grupuje je wg. gościa. W rezultacie można szybko sprawdzić w których Jan Kowalski odcinkach występował (tytuł odcinka, sezon, odcinek, data) - Kowalski akurat nie występował. ;) Potrzeba matką wynalazków, a nowicjuszom może się to przydać, także do dzieła!

Tabela ma strukturę:

<table id="episodesTable">
  <tr>
    <th>Osoba</td>
    <th>Odcinki</td>
  </tr>
  <tr>
    <td>{Imię Nazwisko}</td>
    <td>
      <ul>
        <li><a href="{url}" target="_blank"><span class="episodeTitle">{TYTUŁ}</span> (sezon {numer}, odcinek {numer}, {data})</a></li>
      </ul>
    </td>
  </tr>
</table>

Od czego zacząć? Definiujemy kluczowe zmienne

var si, //searchInput
t, //table
tr; //wszystkie wiersze z tabeli

Następnie przypisujemy do nich wartości, korzystamy przy tym z querySelectora.

si = document.querySelector('#searchPlace');
t = document.querySelector('#episodesTable');
tr = t.querySelectorAll('tr');

Przed tabelą wstawiamy prosty input w którym będziemy wprowadzać zapytanie

<input type="text" placeholder="Wyszukaj w tytułach..." id="searchPlace" />

Definiujemy funkcję wyszukiwania search(e) oraz dodajemy do si w momencie kiedy zostanie "podniesiony" przycisk.

function search(e) {
...
};
        
si.addEventListener('keyup', search);

Skupmy się teraz na funkcji wyszukiwania. Dla uproszczenia dodajemy w stylach klasę która ma za zadanie ukryć element wówczas kiedy zostanie do niego przypisana ta klasa:

.hide {
  display: none;
}

Pobieramy wartość z pola wyszukiwania oraz zmniejszamy wszystkie znaki, dzięki temu ułatwieniu bez znaczenia będzie czy użytkownik będzie wpisywać wartość z małej czy z dużej litery. Później w trakcie porównywania docenisz ten zabieg. Iterujemy wszystkie wiersze w pętli for każdorazowo pobierając wartość do porównania z odpowiedniego elementu. W moim przypadku celowo wyodrębniłem tytuł od informacji o odcinku w celu eliminacji zamieszania w trakcie wyszukiwania:

for (let row of tr) {
   let title = row.querySelector('.episodesTitle');

  if (title === null) {
    continue;
  }

  ...
}

W moim przypadku zdarzały się elementy które nie zawierały elementu .episodesTitle z tego względu, że nie ma ich po prostu w nagłówku tabeli, w tym przypadku pomijamy wykonywanie kodu słowem continue, w innym przypadku kod generował by błąd.

Dalej w pętli pobieramy zawartość elementu z tytułem oraz zmniejszamy znaki w celu porównania:

let titleContent = title.innerHTML.toLowerCase();
if (!titleContent.includes(val)) {
  row.classList.add('hide');
}
else {
  row.classList.remove('hide');
}

Funkcja includes sprawdza, podciąg czy znajduje się w ciągu. Jeśli nie, dodaje do wiersza klasę stylu hide która ma na celu ukrycie go, w przeciwnym przypadku usuwa tą klasę. Tak oto każdorazowo po każdym wciśnięciu przycisku na klawiaturze wykonywana jest ta funkcja, a tabela jest przeszukiwania dynamicznie, od razu pokazując wynik wyszukiwania. Metoda ta jest dobra dla wyszukiwania elementów z małych zbiorów.

Dla podsumowania przedstawiam cały kod js:

(function(){
  var si,t,tr;
  si = document.querySelector('#searchPlace');
  t = document.querySelector('#episodesTable');
  tr = t.querySelectorAll('tr');
  
  function search(e) {
    let val = e.target.value.toLowerCase();
    for (let row of tr) {
      let title = row.querySelector('.episodeTitle');
      
      if (title === null)
        continue;
      
      let titleContent = title.innerHTML.toLowerCase();
      if (!titleContent.includes(val)) {
        row.classList.add('hide');
      }
      else {
        row.classList.remove('hide');
      }
    }
  };
  
  si.addEventListener('keyup', search);
})();

Przypominam początkującym, że aby kod poprawnie działał, należy go umieścić na końcu strony tuż przed tagiem body.