Фильтровать несколько столбцов таблицы - PullRequest
1 голос
/ 19 сентября 2019

Я использую таблицу данных из Framework7 , которая динамически создается с данными JSON, и я пытаюсь сделать входной фильтр фильтра функциональным.Используя другие примеры, показанные при переполнении стека, я смог успешно выполнить фильтрацию по первому столбцу:

HTML

<input type="text" id="brandFilter" onkeyup="filterTable()" placeholder="Filter">

JS

function filterTable() {  
  var input, filter, table, tr, td, i, txtValue;
  input = document.getElementById("brandFilter");
  filter = input.value.toUpperCase();
  table = document.getElementById("productList");
  tr = table.getElementsByTagName("tr");  
  for (i = 0; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td")[0];
    if (td) {
      txtValue = td.textContent || td.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }
    }
  }
}

enter image description here

Я не могу понять, как улучшить этот сценарий, чтобы можно было далее фильтровать таблицу, используя входные данные в столбцах 2 и 3?

<input type="text" id="modelFilter" onkeyup="filterTable()" placeholder="Filter">
<input type="text" id="energyFilter" onkeyup="filterTable()" placeholder="Filter">

Какие-нибудь простые решения, поскольку я все еще новичок?

Ответы [ 2 ]

0 голосов
/ 19 сентября 2019

Вы можете создать список терминов на основе их положения в столбце и сохранить тип ввода и значение.

Затем можно выполнить цикл по каждой строке и определить, хотите ли вы отобразить его, на основетекстовое содержимое каждой ячейки и соответствующий ей термин.

function onFilterChange(e) {
  let table = findParentBySelector(e.target, 'table');
  var terms = [].slice.call(table.querySelectorAll('.input')).map(el => {
    let item = el.querySelector('input, select');
    return { type : item.tagName, value : item.value };
  });
  table.querySelectorAll('tbody tr').forEach(tr => {
    let visible = [].slice.call(tr.querySelectorAll('td')).every((td, i) => {
      if (terms[i].type === 'SELECT' && terms[i].value === 'All') return true;
      let text = td.innerHTML.trim();
      return text != '' ? text.indexOf(terms[i].value) > -1 : true;
    });
    tr.classList[visible ? 'remove' : 'add']('hidden-row');
  });
}

Demo

var data = `2,Jane Doe,jane.doe@com,Female
3,Vladimir Kharlampidi,vladimir@google.com,Male
4,Jennifer Doe,jennifer@doe.com,Female`.split('\n');

let tbody = document.querySelector('.data-table table tbody')
data.forEach(r => {
  let tr = document.createElement('TR');
  r.split(/,\s*?/g).forEach(c => {
    let td = document.createElement('TD');
    td.innerHTML = c;
    tr.appendChild(td);
  });
  tbody.appendChild(tr);
});

document.querySelectorAll('.input').forEach(el => {
  el.querySelectorAll('input').forEach(x => x.addEventListener('keyup', onFilterChange));
  el.querySelectorAll('*').forEach(x => x.addEventListener('change', onFilterChange));
});

function onFilterChange(e) {
  let table = findParentBySelector(e.target, 'table'),
    caseInsensitive = table.getAttribute('data-ignore-case') === 'true',
    terms = [].slice.call(table.querySelectorAll('.input')).map(el => {
      let item = el.querySelector('input, select');
      return {
        type : item.tagName,
        value : (v => caseInsensitive ? v.toLowerCase() : v)(item.value)
      };
    });
  table.querySelectorAll('tbody tr').forEach(tr => {
    let visible = [].slice.call(tr.querySelectorAll('td')).every((td, i) => {
      let text = (t => caseInsensitive ? t.toLowerCase() : t)(td.textContent.trim());
      if (terms[i].type === 'SELECT') {
       if (terms[i].value.toUpperCase() === 'ALL') return true;
       return terms[i].value === text;
      }
      return text != '' ? text.indexOf(terms[i].value) > -1 : true;
    });
    tr.classList.toggle('hidden-row', !visible);
  });
}

// https://stackoverflow.com/a/14234618/1762224
// Note: Modified as a recursive routine
function findParentBySelector(el, target) {
  return el != null ? el && ![].slice.call(typeof target === 'string' ? (target = document.querySelectorAll(target)) : target).some(c => c == el) ? findParentBySelector(el.parentNode, target) : el : null;
}
body {
  background: #444 !important;
}

.data-table {
  width: 96% !important;
  margin: 1em auto !important;
  padding: 0.5em;
}

/** Toggled */
.hidden-row {
  display: none;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/framework7/4.5.0/css/framework7.bundle.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/framework7/4.5.0/js/framework7.bundle.min.js"></script>
<div class="card data-table">
  <table data-ignore-case="true">
    <thead>
      <tr>
        <th class="input-cell">
          <span class="table-head-label">ID</span>
          <div class="input" style="width: 50px">
            <input type="number" placeholder="Filter">
          </div>
        </th>
        <th class="input-cell">
          <span class="table-head-label">Name</span>
          <div class="input">
            <input type="text" placeholder="Filter">
          </div>
        </th>
        <th class="input-cell">
          <span class="table-head-label">Email</span>
          <div class="input">
            <input type="text" placeholder="Filter">
          </div>
        </th>
        <th class="input-cell">
          <span class="table-head-label">Gender</span>
          <div class="input input-dropdown">
            <select>
              <option value="All">All</option>
              <option value="Male">Male</option>
              <option value="Female">Female</option>
            </select>
          </div>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>John Doe</td>
        <td>john@doe.com</td>
        <td>Male</td>
      </tr>
    </tbody>
  </table>
</div>

Исходный ответ

  1. Добавьте класс в поля поиска с атрибутом данных:

    $('<input>').addClass('search-field').data('field', field))
    
  2. Добавьте имя поля в ячейки таблицы.

    $('<td>').text(rec[field]).data('field-name', field)
    
  3. Реализуйте карту поиска с терминами и отфильтруйте каждую строкуесли все критерии соответствуют текстовому содержимому каждой ячейки.Если термин для столбца пуст, предположим, что true.

    var $table = $.tableFromJson(data).addClass('stylized').appendTo('body');
    $table.on('keyup', '.search-field', function(e) {
      // Map fields to pairs and then reduce into a map.
      let terms = $('.search-field').map(function(i, field) {
        return { field : $(field).data('field'), value : $(field).val().trim() };
      }).toArray().reduce(function(terms, pair) {
        return Object.assign(terms, { [pair.field] : pair.value });
      }, {});
    
      let len = Object.keys(terms).length; // Store the length of the keys
    
      // Find the parent (table) of the search field that you modified and locate the rows
      $(e.target).closest('table').find('tbody tr').each(function(i, tr) {
        // Toggle the row visibility
        $(tr).toggle($(tr).find('td').filter(function(j, td) {
          let term =  terms[$(td).data('field-name')];
    
          // If not empty, locate the term within the text of the cell
          return term != '' ? $(td).text().trim().indexOf(term) > -1 : true;
        }).length === len);
      });
    });
    

Демо

(function($) {
  $.reduce = function(arr, fnReduce, valueInitial) {
    if (Array.prototype.reduce) {
      return Array.prototype.reduce.call(arr, fnReduce, valueInitial);
    }
    $.each(arr, function(i, value) {
      valueInitial = fnReduce.call(null, valueInitial, value, i, arr);
    });
    return valueInitial;
  };
  $.fn.reduce = function(fnReduce, valueInitial) {
    return $.reduce(this, fnReduce, valueInitial);
  };
  $.fn.renderTable = function(data, options) {
    options = options || {};
    let ignoreCase = options.ignoreCase, fields = Object.keys(data[0]);
    return this.renderHeaders(fields).renderRows(fields, data)
      .on('keyup', '.search-field', function(e) {
        let terms = $('.search-field').reduce(function(m, field) {
            return Object.assign(m, {
              [$(field).data('field')]: (function(val) {
                return ignoreCase && val ? val.toLowerCase() : val;
              })($(field).val().trim())
            });
          }, {}), len = Object.keys(terms).length;
        $(e.target).closest('table').find('tbody tr').each(function(i, tr) {
          $(tr).toggle($(tr).find('td').filter(function(j, td) {
            let term = terms[$(td).data('field-name')];
            return term != '' ? (function(text) {
              return ignoreCase && text ? text.toLowerCase() : text;
            })($(td).text().trim()).indexOf(term) > -1 : true;
          }).length === len);
        });
      });
  };
  $.fn.renderHeaders = function(fields) {
    return this.append($.renderHeaders(fields));
  }
  $.fn.renderRows = function(fields, data) {
    return this.append($.renderRows(fields, data));
  };
  $.tableFromJson = function(data, options) {
    return $('<table>').renderTable(data, options)
      .toggleClass('stylized', (options || {}).stylized);
  };
  $.renderHeaders = function(fields) {
    return $('<thead>').append($('<tr>').append(fields
      .map(field => $('<th>')
        .append($('<div>').text(field))
        .append($('<input>').addClass('search-field').data('field', field)))));
  };
  $.renderRows = function(fields, data) {
    return $('<tbody>').append(data
      .map((rec, row) => $('<tr>').append(fields
        .map((field, col) => $('<td>').text(rec[field]).data('field-name', field)))));
  };
})(jQuery);

var data = [
  { "brand" : "Bosch", "model" : 333, "energyUse" : "A"   },
  { "brand" : "Bosch", "model" : 456, "energyUse" : "A++" }
];

$.tableFromJson(data, { ignoreCase: true, stylized: true }).appendTo('body');
body {
  padding: 0.25em;
}

h1 {
  font-weight: bold;
  margin-top: 0.75em;
  margin-bottom: 0.33em;
}

table.stylized {
  font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
  font-size: 12px;
  text-align: left;
  border-collapse: collapse;
  margin: 4px;
  width: 600px;
}

table.stylized thead th {
  text-transform: capitalize;
  font-size: 13px;
  color: #039;
  background: #b9c9fe;
  padding: 6px;
  cursor: pointer;
}

table.stylized thead th input {
  background: #f2f5ff;
  color: #039;
  font-size: smaller;
}

table.stylized tbody tr:nth-child(odd) {
  background: #f2f5ff;
}

table.stylized tbody tr:nth-child(even) {
  background: #e8edff;
}

table.stylized tbody td {
  border-top: 1px solid #fff;
  color: #669;
  padding: 6px;
}

table.stylized tbody tr:hover td {
  background: #d0dafd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Примечание: Плагин jQuery для генерации таблиц в этой демонстрации основан на плагине для сортируемых таблиц Я ранее реализовал.

0 голосов
/ 19 сентября 2019

Если вы хотите изменить фильтр для каждого столбца, просто измените это:

function filterTable(column) {  // add a parameter
  var input, filter, table, tr, td, i, txtValue;
  input = document.getElementById("brandFilter");
  filter = input.value.toUpperCase();
  table = document.getElementById("productList");
  tr = table.getElementsByTagName("tr");  
  for (i = 0; i < tr.length; i++) {
  td = tr[i].getElementsByTagName("td")[0];// change this
  td = tr[i].getElementsByTagName("td")[column];// to this
    if (td) {
      txtValue = td.textContent || td.innerText;
      if (txtValue.toUpperCase().indexOf(filter) > -1) {
        tr[i].style.display = "";
      } else {
        tr[i].style.display = "none";
      }
    }
  }
}

Таким образом, вы передаете индекс столбца в качестве значения для фильтрации по столбцу

Надеюсь, это поможет

...