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.


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


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

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>

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

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>


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";
        }
      } 
    }
  }
}

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>



-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);
        });
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.