Jak przeprowadzić wyszukiwanie i filtrowanie w czasie rzeczywistym w tabeli HTML


139

Od jakiegoś czasu szukam w Google i przeszukuję Stack Overflow, ale po prostu nie mogę obejść tego problemu.

Mam standardową tabelę HTML zawierającą, powiedzmy, owoce. Tak jak to:

<table>
   <tr>
      <td>Apple</td>
      <td>Green</td>
   </tr>
   <tr>
      <td>Grapes</td>
      <td>Green</td>
   </tr>
   <tr>
      <td>Orange</td>
      <td>Orange</td>
   </tr>
</table>

Powyżej mam pole tekstowe, które chciałbym przeszukać w tabeli jako typ użytkownika. Tak więc, jeśli wpiszą Grena przykład, pomarańczowy wiersz tabeli zniknie, pozostawiając jabłko i winogrona. Jeśli kontynuowali i wpisywali, Green Grwiersz Apple powinien zniknąć, pozostawiając tylko winogrona. Mam nadzieję, że to jasne.

I jeśli użytkownik usunie część lub całość swojego zapytania z pola tekstowego, chciałbym, aby wszystkie wiersze, które teraz pasują do zapytania, pojawiły się ponownie.

Chociaż wiem, jak usunąć wiersz tabeli w jQuery, nie mam pojęcia, jak przeprowadzić wyszukiwanie i selektywnie usuwać wiersze na tej podstawie. Czy jest na to proste rozwiązanie? Albo wtyczka?

Gdyby ktokolwiek mógł wskazać mi właściwy kierunek, byłoby wspaniale.

Dziękuję Ci.


Odpowiedzi:


307

Stworzyłem te przykłady.

Proste wyszukiwanie indeksu

var $rows = $('#table tr');
$('#search').keyup(function() {
    var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();

    $rows.show().filter(function() {
        var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
        return !~text.indexOf(val);
    }).hide();
});

Demo : http://jsfiddle.net/7BUmG/2/

Wyszukiwanie wyrażeń regularnych

Bardziej zaawansowana funkcjonalność wykorzystująca wyrażenia regularne pozwoli Ci wyszukiwać słowa w dowolnej kolejności w wierszu. Będzie działać tak samo, jeśli wpiszesz apple greenlub green apple:

var $rows = $('#table tr');
$('#search').keyup(function() {

    var val = '^(?=.*\\b' + $.trim($(this).val()).split(/\s+/).join('\\b)(?=.*\\b') + ').*$',
        reg = RegExp(val, 'i'),
        text;

    $rows.show().filter(function() {
        text = $(this).text().replace(/\s+/g, ' ');
        return !reg.test(text);
    }).hide();
});

Demo : http://jsfiddle.net/dfsq/7BUmG/1133/

Obalić

Wdrażając filtrowanie tabel z wyszukiwaniem w wielu wierszach i kolumnach, bardzo ważne jest, aby wziąć pod uwagę wydajność i szybkość / optymalizację wyszukiwania. Mówiąc po prostu, nie powinieneś uruchamiać funkcji wyszukiwania przy każdym naciśnięciu klawisza, nie jest to konieczne. Aby zapobiec zbyt częstemu uruchamianiu filtrowania, należy je usunąć. Powyższy przykład kodu stanie się:

$('#search').keyup(debounce(function() {
    var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
    // etc...
}, 300));

Możesz wybrać dowolną implementację debounce, na przykład z Lodash _.debounce , lub możesz użyć czegoś bardzo prostego, jak używam w następnych demonstracjach (debounce stąd ): http://jsfiddle.net/7BUmG/6230/ i http: / /jsfiddle.net/7BUmG/6231/ .


3
Jestem całkiem zielony z tych rzeczy, ale jeśli chcę włączyć to na moim stole, czy po prostu trzeba zmienić #tabledo idmojego stołu? Czy potrzebne byłyby dodatkowe zmiany do pracy z tagami <thead>i <tbody>tagami? Dołączyłem skrypt i html z linku jsfiddle, zmieniając #id, ale nie otrzymuję żadnego filtrowania.
JoshP

10
@JoshP Sctipt działa ze wszystkimi wierszami. Jeśli chcesz filtrować tylko te, które znajdują się wewnątrz <tbody>, powinieneś zmienić na var $rows = $('#id-of-your-table tbody tr');.
dfsq

2
@JoshP Nie, nie jest wymagane nic poza jQuery. Po prostu upewnij się, że uruchamiasz kod w DOMReady lub po załadowaniu HTML.
dfsq

2
Poleciłbym udoskonalenie tego podejścia, ponieważ jest ono dość zasobochłonne. Umieść wszystkie dopracowane ciągi w tablicy obiektów z dwoma polami: odwołanie do elementu <tr>DOMElement i ciąg. W ten sposób keyup()przeszukujesz te ciągi (co jest o wiele szybsze) i masz odpowiednie wiersze gotowe do manipulacji. Ta pierwsza kosztowna procedura konfiguracji powinna zostać wykonana tylko raz, zaraz po załadowaniu. Wszystkie te zmiany to tylko drobne poprawki, rzeczywista centralna część nadal pozostaje taka, jak pokazano w tej odpowiedzi. Takie podejście jest również możliwe i całkiem łatwe do zaimplementowania bez jQuery.
pid

2
@confusedMind Użyj $('#table tr:not(:first)')selektora.
dfsq

10

Mam do tego wtyczkę jquery. Używa również jquery-ui. Możesz zobaczyć przykład tutaj http://jsfiddle.net/tugrulorhan/fd8KB/1/

$("#searchContainer").gridSearch({
            primaryAction: "search",
            scrollDuration: 0,
            searchBarAtBottom: false,
            customScrollHeight: -35,
            visible: {
                before: true,
                next: true,
                filter: true,
                unfilter: true
            },
            textVisible: {
                before: true,
                next: true,
                filter: true,
                unfilter: true
            },
            minCount: 2
        });

8

Tutaj jest najlepszym rozwiązaniem dla poszukiwania wewnątrz tabeli HTML, obejmując wszystkie tabeli (wszystkie td, tr w tabeli), czystego javascript i jak zwarcia , jak to możliwe:

<input id='myInput' onkeyup='searchTable()' type='text'>

<table id='myTable'>
   <tr>
      <td>Apple</td>
      <td>Green</td>
   </tr>
   <tr>
      <td>Grapes</td>
      <td>Green</td>
   </tr>
   <tr>
      <td>Orange</td>
      <td>Orange</td>
   </tr>
</table>

<script>
function searchTable() {
    var input, filter, found, table, tr, td, i, j;
    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");
        for (j = 0; j < td.length; j++) {
            if (td[j].innerHTML.toUpperCase().indexOf(filter) > -1) {
                found = true;
            }
        }
        if (found) {
            tr[i].style.display = "";
            found = false;
        } else {
            tr[i].style.display = "none";
        }
    }
}
</script>

3
Aby zabezpieczyć wiersz nagłówka tabeli przed zniknięciem, dodaj identyfikator do wiersza, na przykład: <tr id = 'tableHeader'> i zmień ostatnią instrukcję else na: if (tr [i] .id! = 'TableHeader') {tr [i ] .style.display = "none";} Nie ma o tym wzmianki w pytaniu, ale chciałem, aby obejmowało to, aby było wyczerpujące.
Tarik

Zamiast porównywać identyfikator za pomocą! =, Sugeruję zmianę ostatniego else na to:} else if (! Tr [i] .id.match ('^ tableHeader')) {To pozwala mieć więcej niż jedną tabelę, każda z własnym nagłówkiem. Potrzeba więcej pracy, aby sparametryzować funkcję searchTable, przekazując identyfikator tabeli.
Tom Ekberg,

3

Dziękuję @dfsq za bardzo pomocny kod!

Dokonałem pewnych poprawek i może inne też je lubią. Zapewniłem, że możesz wyszukiwać wiele słów bez ścisłego dopasowania.

Przykładowe wiersze:

  • Jabłka i Gruszki
  • Jabłka i banany
  • Jabłka i Pomarańcze
  • ...

Możesz wyszukać „ap pe” i rozpozna pierwszy wiersz
Możesz wyszukać „jabłko bananowe” i rozpozna drugi wiersz

Demo: http://jsfiddle.net/JeroenSormani/xhpkfwgd/1/

var $rows = $('#table tr');
$('#search').keyup(function() {
  var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase().split(' ');

  $rows.hide().filter(function() {
    var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
    var matchesSearch = true;
    $(val).each(function(index, value) {
      matchesSearch = (!matchesSearch) ? false : ~text.indexOf(value);
    });
    return matchesSearch;
  }).show();
});

Solidne wyszukiwanie - musiałem go nieco zmodyfikować, aby zapobiec zniknięciu nagłówków i stopek mojego stołu, zmieniając: var $rows = $('#WorldPlayersTable tr'); na - var $rows = $('#WorldPlayersTable tbody tr');
Drefetr

2

Uważam, że odpowiedź dfsq na jej komentarze jest niezwykle przydatna. Dokonałem kilku drobnych modyfikacji, które mnie dotyczą (i zamieszczam je tutaj, na wypadek, gdyby przydało się to innym).

  1. Używanie classjako haczyków zamiast elementów tabelitr
  2. Wyszukiwanie / porównywanie tekstu w dziecku classpodczas pokazywania / ukrywania rodzica
  3. Zwiększenie wydajności dzięki $rowsjednokrotnemu przechowywaniu elementów tekstowych w tablicy (i unikaniu $rows.lengthobliczeń czasu)

var $rows = $('.wrapper');
var rowsTextArray = [];

var i = 0;
$.each($rows, function() {
  rowsTextArray[i] = $(this).find('.fruit').text().replace(/\s+/g, ' ').toLowerCase();
  i++;
});

$('#search').keyup(function() {
  var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
  $rows.show().filter(function(index) {
    return (rowsTextArray[index].indexOf(val) === -1);
  }).hide();
});
span {
  margin-right: 0.2em;
}
<input type="text" id="search" placeholder="type to search" />

<div class="wrapper"><span class="number">one</span><span class="fruit">apple</span></div>
<div class="wrapper"><span class="number">two</span><span class="fruit">banana</span></div>
<div class="wrapper"><span class="number">three</span><span class="fruit">cherry</span></div>
<div class="wrapper"><span class="number">four</span><span class="fruit">date</span></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


2

Czyste rozwiązanie JavaScript:

Działa dla WSZYSTKICH kolumn i bez rozróżniania wielkości liter:

function search_table(){
  // Declare variables 
  var input, filter, table, tr, td, i;
  input = document.getElementById("search_field_input");
  filter = input.value.toUpperCase();
  table = document.getElementById("table_id");
  tr = table.getElementsByTagName("tr");

  // Loop through all table rows, and hide those who don't match the search query
  for (i = 0; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td") ; 
    for(j=0 ; j<td.length ; j++)
    {
      let tdata = td[j] ;
      if (tdata) {
        if (tdata.innerHTML.toUpperCase().indexOf(filter) > -1) {
          tr[i].style.display = "";
          break ; 
        } else {
          tr[i].style.display = "none";
        }
      } 
    }
  }
}

1

możesz użyć natywnego javascript w ten sposób

<script>
function myFunction() {
  var input, filter, table, tr, td, i;
  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) {
      if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }
    }       
  }
}
</script>



-1

Jeśli możesz oddzielić HTML i dane, możesz użyć bibliotek zewnętrznych, takich jak zbiory danych lub ta, którą utworzyłem. https://github.com/thehitechpanky/js-bootstrap-tables

Ta biblioteka używa funkcji keyup do przeładowywania danych tablicowych i dlatego wygląda na to, że działa jak wyszukiwanie.

function _addTableDataRows(paramObjectTDR) {
    let { filterNode, limitNode, bodyNode, countNode, paramObject } = paramObjectTDR;
    let { dataRows, functionArray } = paramObject;
    _clearNode(bodyNode);
    if (typeof dataRows === `string`) {
        bodyNode.insertAdjacentHTML(`beforeend`, dataRows);
    } else {
        let filterTerm;
        if (filterNode) {
            filterTerm = filterNode.value.toLowerCase();
        }
        let serialNumber = 0;
        let limitNumber = 0;
        let rowNode;
        dataRows.forEach(currentRow => {
            if (!filterNode || _filterData(filterTerm, currentRow)) {
                serialNumber++;
                if (!limitNode || limitNode.value === `all` || limitNode.value >= serialNumber) {
                    limitNumber++;
                    rowNode = _getNode(`tr`);
                    bodyNode.appendChild(rowNode);
                    _addData(rowNode, serialNumber, currentRow, `td`);
                }
            }
        });
        _clearNode(countNode);
        countNode.insertAdjacentText(`beforeend`, `Showing 1 to ${limitNumber} of ${serialNumber} entries`);
    }
    if (functionArray) {
        functionArray.forEach(currentObject => {
            let { className, eventName, functionName } = currentObject;
            _attachFunctionToClassNodes(className, eventName, functionName);
        });
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.