Cómo realizar una búsqueda y filtro en tiempo real en una tabla HTML

139

He estado buscando en Google y buscando Stack Overflow por un tiempo, pero no puedo solucionar este problema.

Tengo una tabla HTML estándar que contiene, por ejemplo, fruta. Al igual que:

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

Por encima de esto, tengo un cuadro de texto, que me gustaría buscar en la tabla a medida que un usuario escribe. Entonces, si Greescriben, por ejemplo, la fila naranja de la tabla desaparecería, dejando Apple y Grapes. Si Green Grcontinúan y escriben, la fila de Apple debería desaparecer, dejando solo uvas. Espero que esto quede claro.

Y, si el usuario elimina parte o la totalidad de su consulta del cuadro de texto, me gustaría que reaparezcan todas las filas que ahora coinciden con la consulta.

Si bien sé cómo eliminar una fila de la tabla en jQuery, tengo poca idea sobre cómo hacer la búsqueda y eliminar filas selectivamente en función de esto. ¿Hay una solución simple para esto? O un complemento?

Si alguien pudiera señalarme en la dirección correcta, sería genial.

Gracias.

samiles
fuente

Respuestas:

307

Creé estos ejemplos.

Índice simple de búsqueda

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

Demostración : http://jsfiddle.net/7BUmG/2/

Búsqueda de expresiones regulares

La funcionalidad más avanzada que usa expresiones regulares le permitirá buscar palabras en cualquier orden en la fila. Funcionará igual si escribe 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();
});

Demostración : http://jsfiddle.net/dfsq/7BUmG/1133/

Debounce

Cuando implementa el filtrado de tablas con búsqueda en varias filas y columnas, es muy importante que considere el rendimiento y la velocidad / optimización de búsqueda. Simplemente decir que no debe ejecutar la función de búsqueda en cada pulsación de tecla, no es necesario. Para evitar que el filtrado se ejecute con demasiada frecuencia, debe eliminarlo. El ejemplo de código anterior se convertirá en:

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

Puede elegir cualquier implementación de eliminación de rebotes, por ejemplo, de Lodash _.debounce , o puede usar algo muy simple como el que uso en las próximas demostraciones (debounce desde aquí ): http://jsfiddle.net/7BUmG/6230/ y http: / /jsfiddle.net/7BUmG/6231/ .

dfsq
fuente
3
Estoy bastante verde con estas cosas, pero si quiero incorporar esto en mi mesa, ¿solo necesito cambiar #tableel idde mi mesa? ¿Tendría que haber cambios adicionales para trabajar <thead>y <tbody>etiquetas? He incluido el script y el html desde el enlace jsfiddle, cambiando el #id, pero no obtengo filtrado.
JoshP
10
@JoshP Sctipt funciona con todas las filas. Si desea filtrar solo aquellos dentro de los <tbody>que debe cambiar var $rows = $('#id-of-your-table tbody tr');.
dfsq
2
@JoshP No, solo se requiere jQuery. Solo asegúrese de ejecutar su código en DOMReady o después de cargar HTML.
dfsq
2
Recomendaría mejorar este enfoque porque consume bastante recursos. Coloque todas las cadenas refinadas en una matriz de objetos con dos campos: una referencia a <tr>DOMElement y la cadena. De esta manera, al keyup()buscar esas cadenas (que es mucho más rápido) y tener las filas correspondientes listas para ser manipuladas. Ese primer procedimiento de configuración costoso debe ejecutarse solo una vez justo después de la carga. Todos estos cambios son solo correcciones menores, la parte central real aún permanece como se muestra en esta respuesta. Este enfoque también es posible y bastante fácil de implementar sin jQuery.
pid
2
@confusedMind Usar $('#table tr:not(:first)')selector.
dfsq
10

Tengo un complemento jquery para esto. Utiliza jquery-ui también. Puede ver un ejemplo aquí 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
        });
Yorgo
fuente
8

Aquí está la mejor solución para buscar dentro de la tabla HTML mientras cubre toda la tabla , (todo td, tr en la tabla), javascript puro y lo más breve posible:

<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>
Tarik
fuente
3
Para proteger la fila del encabezado de la tabla para que no desaparezca, agregue la identificación a la fila como: <tr id = 'tableHeader'> y cambie la instrucción final else a: if (tr [i] .id! = 'TableHeader') {tr [i ] .style.display = "none";} No se menciona en la pregunta, pero quería que lo cubriera para que fuera completo.
Tarik
En lugar de comparar la identificación usando! =, Sugiero cambiar el final más a esto:} else if (! Tr [i] .id.match ('^ tableHeader')) {Esto permite que uno tenga más de una tabla, cada una con su propio encabezado. Se necesita más trabajo para parametrizar la función searchTable pasando la identificación de la tabla.
Tom Ekberg
3

¡Gracias @dfsq por el código tan útil!

He hecho algunos ajustes y tal vez a otros también les gusten. Me aseguré de que puede buscar varias palabras, sin tener una coincidencia estricta.

Filas de ejemplo:

  • Manzanas y peras
  • Manzanas y plátanos
  • Manzanas y naranjas
  • ...

Podrías buscar 'ap pe' y reconocería la primera fila
Podrías buscar 'banana apple' y reconocería la segunda fila

Demostración: 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();
});
Sormano
fuente
Búsqueda sólida: tuve que modificarlo ligeramente para evitar que los encabezados y pies de página de mi tabla desaparecieran, cambiando: var $rows = $('#WorldPlayersTable tr'); a - var $rows = $('#WorldPlayersTable tbody tr');
Drefetr
2

Encontré que la respuesta de dfsq a sus comentarios es extremadamente útil. Hice algunas modificaciones menores aplicables a mí (y lo estoy publicando aquí, en caso de que sea de alguna utilidad para otros).

  1. Utilizando classcomo ganchos, en lugar de elementos de tablatr
  2. Buscar / comparar texto dentro de un niño classmientras se muestra / se oculta el padre
  3. Haciéndolo más eficiente almacenando los $rowselementos de texto en una matriz solo una vez (y evitando el $rows.lengthcálculo de tiempos)

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>

Tostada Kaya
fuente
2

Solución Javascript Pura:

Funciona para TODAS las columnas y mayúsculas y minúsculas:

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";
        }
      } 
    }
  }
}
Natesh Bhat
fuente
1

puedes usar javascript nativo como este

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

Omar Maher
fuente
0

El complemento Datatable JS también es una buena alternativa para aceptar la función de búsqueda para la tabla html

var table = $('#example').DataTable();

// #myInput is a <input type="text"> element
$('#myInput').on( 'keyup', function () {
    table.search( this.value ).draw();
} );

https://datatables.net/examples/basic_init/zero_configuration.html

Aditya
fuente
-1

Si puede separar html y datos, puede usar bibliotecas externas como tablas de datos o la que yo creé. https://github.com/thehitechpanky/js-bootstrap-tables

Esta biblioteca utiliza la función keyup para recargar datos de tabla y, por lo tanto, parece funcionar como la búsqueda.

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);
        });
    }
}
Pankaj Jain
fuente