Comment effectuer une recherche et filtrer en temps réel sur un tableau HTML

139

J'ai cherché sur Google et recherché Stack Overflow pendant un certain temps, mais je ne peux tout simplement pas contourner ce problème.

J'ai un tableau HTML standard, contenant, par exemple, des fruits. Ainsi:

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

Au-dessus de cela, j'ai une zone de texte, que je voudrais rechercher dans le tableau en tant que type d'utilisateur. Donc, s'ils Gretapent par exemple, la ligne orange du tableau disparaîtrait, laissant la pomme et les raisins. S'ils Green Grcontinuaient et tapaient, la rangée Apple devrait disparaître, ne laissant que des raisins. J'espère que ceci est clair.

Et si l'utilisateur supprime une partie ou la totalité de sa requête de la zone de texte, je souhaite que toutes les lignes qui correspondent maintenant à la requête réapparaissent.

Bien que je sache comment supprimer une ligne de table dans jQuery, j'ai peu d'idée sur la façon de faire la recherche et de supprimer des lignes de manière sélective en fonction de cela. Y a-t-il une solution simple à cela? Ou un plugin?

Si quelqu'un pouvait me diriger dans la bonne direction, ce serait génial.

Je vous remercie.

Samiles
la source

Réponses:

307

J'ai créé ces exemples.

Index de recherche simple

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

Démo : http://jsfiddle.net/7BUmG/2/

Recherche d'expression régulière

Des fonctionnalités plus avancées utilisant des expressions régulières vous permettront de rechercher des mots dans n'importe quel ordre dans la ligne. Cela fonctionnera de la même manière si vous tapez apple greenou 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();
});

Démo : http://jsfiddle.net/dfsq/7BUmG/1133/

Rebondir

Lorsque vous implémentez le filtrage de table avec recherche sur plusieurs lignes et colonnes, il est très important de prendre en compte les performances et la vitesse de recherche / l'optimisation. En disant simplement que vous ne devez pas exécuter la fonction de recherche à chaque frappe, ce n'est pas nécessaire. Pour éviter que le filtrage ne s'exécute trop souvent, vous devez le supprimer. L'exemple de code ci-dessus deviendra:

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

Vous pouvez choisir n'importe quelle implémentation de debounce, par exemple à partir de Lodash _.debounce , ou vous pouvez utiliser quelque chose de très simple comme j'utilise dans les prochaines démos (debounce à partir d' ici ): http://jsfiddle.net/7BUmG/6230/ et http: / /jsfiddle.net/7BUmG/6231/ .

dfsq
la source
3
Je suis assez vert avec ce truc, mais si je veux incorporer cela dans ma table, dois-je juste changer #tablele idde ma table? Des modifications supplémentaires seraient-elles nécessaires pour travailler avec les balises <thead>et <tbody>? J'ai inclus le script et le html du lien jsfiddle, en changeant le #id, mais je n'obtiens aucun filtrage.
JoshP
10
@JoshP Sctipt fonctionne avec toutes les lignes. Si vous souhaitez filtrer uniquement ceux qui se trouvent à l'intérieur du, <tbody>vous devez passer à var $rows = $('#id-of-your-table tbody tr');.
dfsq
2
@JoshP Non, rien d'autre que jQuery n'est requis. Assurez-vous simplement d'exécuter votre code dans DOMReady ou après le chargement du HTML.
dfsq
2
Je recommanderais d'améliorer cette approche car elle consomme beaucoup de ressources. Mettez toutes les chaînes raffinées dans un tableau d'objets avec deux champs: une référence au <tr>DOMElement et la chaîne. De cette façon, keyup()vous recherchez ces chaînes (ce qui est beaucoup plus rapide) et avez les lignes correspondantes prêtes à être manipulées. Cette première procédure de configuration coûteuse doit ensuite être exécutée une seule fois juste après le chargement. Tous ces changements ne sont que des corrections mineures, la partie centrale réelle reste toujours comme indiqué dans cette réponse. Cette approche est également possible et assez facile à implémenter sans jQuery.
pid le
2
@confusedMind Utilisez le $('#table tr:not(:first)')sélecteur.
dfsq
10

j'ai un plugin jquery pour cela. Il utilise également jquery-ui. Vous pouvez voir un exemple ici 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
la source
8

Voici la meilleure solution pour rechercher à l'intérieur d'un tableau HTML tout en couvrant l' ensemble du tableau , (tous td, tr dans le tableau), en javascript pur et aussi court que possible:

<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
la source
3
Pour éviter que la ligne d'en-tête de table ne disparaisse, ajoutez un identifiant à la ligne comme: <tr id = 'tableHeader'> et changez l'instruction else finale en: if (tr [i] .id! = 'TableHeader') {tr [i ] .style.display = "none";} Ce n'est pas mentionné dans la question mais je voulais qu'il couvre cela pour le rendre complet.
Tarik
Au lieu de comparer l'id en utilisant! =, Je suggère de changer le final else en ceci:} else if (! Tr [i] .id.match ('^ tableHeader')) {Cela permet d'avoir plus d'une table, chacune avec leur propre en-tête. Plus de travail est nécessaire pour paramétrer la fonction searchTable en passant l'ID de table.
Tom Ekberg
3

Merci @dfsq pour le code très utile!

J'ai fait quelques ajustements et peut-être d'autres comme eux aussi. J'ai veillé à ce que vous puissiez rechercher plusieurs mots, sans avoir de correspondance stricte.

Exemple de lignes:

  • Pommes et poires
  • Pommes et bananes
  • Pommes et oranges
  • ...

Vous pourriez rechercher «ap pe» et il reconnaîtrait la première ligne
Vous pourriez rechercher «pomme de banane» et il reconnaîtrait la deuxième ligne

Démo: 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
la source
Recherche solide - J'ai dû le modifier légèrement pour éviter que les en-têtes et pieds de page de mon tableau ne disparaissent, en changeant: var $rows = $('#WorldPlayersTable tr'); en - var $rows = $('#WorldPlayersTable tbody tr');
Drefetr
2

J'ai trouvé la réponse de dfsq à ses commentaires extrêmement utiles. J'ai apporté quelques modifications mineures applicables à moi (et je le publie ici, au cas où cela serait d'une certaine utilité pour d'autres).

  1. Utilisation classcomme crochets, au lieu d'éléments de tabletr
  2. Rechercher / comparer du texte dans un enfant classtout en montrant / masquant le parent
  3. Rendre plus efficace en stockant le $rows éléments de texte dans un tableau une seule fois (et en évitant le $rows.lengthcalcul des temps)

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>

Toast Kaya
la source
2

Solution Javascript pur:

Fonctionne pour TOUTES les colonnes et insensible à la casse:

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
la source
1

vous pouvez utiliser du javascript natif comme celui-ci

<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
la source
0

Le plugin Datatable JS est également une bonne alternative pour intégrer la fonction de recherche pour la table 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
la source
-1

Si vous pouvez séparer le HTML et les données, vous pouvez utiliser des bibliothèques externes comme les tables de données ou celle que j'ai créée. https://github.com/thehitechpanky/js-bootstrap-tables

Cette bibliothèque utilise la fonction keyup pour recharger les données de table et semble donc fonctionner comme la recherche.

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