Come eseguire una ricerca e un filtro in tempo reale su una tabella HTML


139

Sono stato su Google e ho cercato Stack Overflow per un po ', ma non riesco a aggirare questo problema.

Ho una tabella HTML standard, contenente, diciamo, frutta. Così:

<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>

Sopra questo ho una casella di testo, che vorrei cercare nella tabella come un utente digita. Quindi, se digitano Greper esempio, la riga arancione del tavolo scompare, lasciando la mela e l'uva. Se hanno continuato e digitato, Green Grla fila di mele dovrebbe sparire, lasciando solo l'uva. Spero che questo sia chiaro.

E, se l'utente dovesse eliminare una parte o tutta la sua query dalla casella di testo, vorrei che tutte le righe che ora corrispondono alla query riappaiano.

Mentre so come rimuovere una riga di tabella in jQuery, ho poca idea su come fare la ricerca e la rimozione selettiva delle righe basate su questo. C'è una soluzione semplice a questo? O un plugin?

Se qualcuno potesse indicarmi la giusta direzione sarebbe geniale.

Grazie.


Risposte:


307

Ho creato questi esempi.

Indice semplice della ricerca

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/

Ricerca di espressioni regolari

Funzionalità più avanzate che utilizzano espressioni regolari ti permetteranno di cercare le parole in qualsiasi ordine nella riga. Funzionerà allo stesso modo se si digita apple greeno 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/

debounce

Quando si implementa il filtro delle tabelle con la ricerca su più righe e colonne, è molto importante considerare le prestazioni e la velocità / ottimizzazione della ricerca. Semplicemente dicendo che non dovresti eseguire la funzione di ricerca su ogni singola sequenza di tasti, non è necessario. Per impedire l'esecuzione troppo frequente del filtro, è necessario rimandarlo. L'esempio di codice sopra diventerà:

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

Puoi scegliere qualsiasi implementazione di debounce, ad esempio da Lodash _.debounce , oppure puoi usare qualcosa di molto semplice come quello che userò nelle prossime demo (debounce da qui ): http://jsfiddle.net/7BUmG/6230/ e http: / /jsfiddle.net/7BUmG/6231/ .


3
Sono abbastanza verde con questa roba, ma se voglio incorporare questo nel mio tavolo, devo solo cambiare il #tablecon iddel mio tavolo? Dovrebbero esserci ulteriori modifiche con cui lavorare <thead>e <tbody>tag? Ho incluso lo script e html dal link jsfiddle, cambiando il #id, ma non ottengo alcun filtro.
JoshP,

10
@JoshP Sctipt funziona con tutte le righe. Se si desidera filtrare solo quelli all'interno, <tbody>è necessario passare a var $rows = $('#id-of-your-table tbody tr');.
dfsq,

2
@JoshP No, non è necessario altro che jQuery. Assicurati di eseguire il codice in DOMReady o dopo aver caricato l'HTML.
dfsq,

2
Consiglierei di migliorare questo approccio perché consuma abbastanza risorse. Inserisci tutte le stringhe raffinate in una matrice di oggetti con due campi: un riferimento a <tr>DOMElement e la stringa. In questo modo, keyup()cerchi quelle stringhe (che è molto più veloce) e hai le righe corrispondenti pronte per essere manipolate. Quella prima procedura di installazione costosa dovrebbe quindi essere eseguita solo una volta subito dopo il caricamento. Tutte queste modifiche sono solo correzioni minori, la parte centrale attuale rimane ancora come mostrato in questa risposta. Questo approccio è anche possibile e abbastanza facile da implementare senza jQuery.
pid

2
@confusedMind Usa il $('#table tr:not(:first)')selettore.
dfsq

10

ho un plugin jquery per questo. Utilizza anche jquery-ui. Puoi vedere un esempio qui 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

Ecco la migliore soluzione per la ricerca all'interno della tabella HTML coprendo tutta la tabella , (tutte td, tr nella tabella), javascript puro e il più breve possibile:

<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
Per proteggere la riga dell'intestazione della tabella dalla scomparsa, aggiungi id alla riga come: <tr id = 'tableHeader'> e modifica l'istruzione else finale in: if (tr [i] .id! = 'TableHeader') {tr [i ] .style.display = "none";} Non è menzionato nella domanda ma volevo che lo coprisse per renderlo completo.
Tarik,

Invece di confrontare l'id usando! =, Suggerisco di cambiare il finale else in questo:} else if (! Tr [i] .id.match ('^ tableHeader')) {Questo permette di avere più di una tabella, ciascuno con la propria intestazione. È necessario più lavoro per parametrizzare la funzione searchTable passando l'id della tabella.
Tom Ekberg,

3

Grazie @dfsq per il codice molto utile!

Ho apportato alcune modifiche e forse anche altre come loro. Ti ho assicurato che puoi cercare più parole, senza una corrispondenza rigorosa.

Righe di esempio:

  • Mele e Pere
  • Mele e banane
  • Mele e arance
  • ...

Potresti cercare 'ap pe' e riconoscerebbe la prima riga
Potresti cercare 'banana apple' e riconoscerebbe la seconda riga

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();
});

Ricerca solida - Ho dovuto modificarlo leggermente per evitare che le intestazioni e i piè di pagina del mio tavolo scomparissero, cambiando: var $rows = $('#WorldPlayersTable tr'); in - var $rows = $('#WorldPlayersTable tbody tr');
Drefetr

2

Ho trovato estremamente utile la risposta di dfsq ai suoi commenti. Ho apportato alcune modifiche minori applicabili a me (e lo sto pubblicando qui, nel caso in cui sia di qualche utilità per altri).

  1. Usando classcome ganci, anziché elementi della tabellatr
  2. Ricerca / confronto di testo all'interno di un bambino class mentre mostra / nasconde il genitore
  3. Rendendolo più efficiente archiviando gli $rowselementi di testo in un array una sola volta (ed evitando il $rows.lengthcalcolo dei tempi)

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

Soluzione Javascript pura:

Funziona con TUTTE le colonne e senza distinzione tra maiuscole e minuscole:

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

puoi usare javascript nativo in questo modo

<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

Se riesci a separare html e dati, puoi usare librerie esterne come datatables o quello che ho creato. https://github.com/thehitechpanky/js-bootstrap-tables

Questa libreria utilizza la funzione keyup per ricaricare tabledata e quindi sembra funzionare come la ricerca.

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);
        });
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.