使用跨多列的多个复选框过滤表格

问题描述 投票:0回答:1

我有一个表,需要根据多列进行过滤,我的示例使用复选框来过滤 5 列,某些列是隐藏的,不会显示在表中,但仍然可以进行过滤。

我需要它如何工作的示例:

  • 如果没有选择过滤器,则默认显示所有行,目前表格默认为空,需要选中复选框才能显示行。

  • 如果选中“月份”过滤器“MAR”,则会显示满足该条件的 4 行,然后我添加语言过滤器“法语”和“西班牙语”,并且只会显示满足两个过滤器条件的 3 行。然后,我取消选中“语言”过滤器并检查“房屋”过滤器“无”,仅显示满足新条件的 1 行。

我当前的尝试存在一些问题,例如过滤器类别未正确地与在一起,因此当选择“Ron”和“Mar”时,结果包括与“Ron”不匹配的其他名称。 另一个问题是,当清除过滤器时,由于先前的过滤器而隐藏的许多行不会变得可见。

可用示例在这里: https://codepen.io/ashleigh-leader/pen/BaXvOqO

function filter(event, filterCol) {
  let element = event.target;
  let condt1 = document.getElementsByClassName(filterCol);
  for (let i = 0; i < condt1.length; i++) {
    if (condt1[i].innerHTML.toLowerCase() == element.value.toLowerCase()) {
      if (element.checked == true) {
        condt1[i].parentElement.style = ""
      } else {
        condt1[i].parentElement.style = "display:none"
      }
    }
  }
}

document.querySelectorAll('.option1')
  .forEach(input => input.addEventListener('input', ()=>filter(event,"check1")));
  
  
document.querySelectorAll('.option2')
  .forEach(input => input.addEventListener('input', ()=>filter(event,"check2")));
  
  
document.querySelectorAll('.option3')
  .forEach(input => input.addEventListener('input', ()=>filter(event,"check3")));
  
  
document.querySelectorAll('.option4')
  .forEach(input => input.addEventListener('input', ()=>filter(event,"check4")));
  
  
document.querySelectorAll('.option5')
  .forEach(input => input.addEventListener('input', ()=>filter(event,"check5")));
#myTable {
border-collapse: collapse;
width: 100%; 
border: 1px solid #ddd;
font-size: 14px;
margin: 5px;
}
  
#myTable th, #myTable td {
text-align: left;
padding: 12px;
}
  
#myTable tr {
border-bottom: 1px solid #ddd;
color: #58585B;
font-family: "museo-sans-rounded";
font-size: 14px;
font-weight: 300px;
}
  
#myTable tr.header {
background-color: #862B90;
background-size: contain;
color: white;
font-family: "museo-sans-rounded";
font-size: 16px;
font-weight: 300px;
}

#myTable tr:hover {
font-family: "museo-sans-rounded";
font-size: 16px;
font-weight: 300px;
}

#myTable td.month-pill {
align-self: center;
background-color: #FFC52E;
border: none;
color: #FFC52E;
padding: 10px;
text-align: center;
text-decoration: none;
display: inline-block;
margin: 4px;
border-radius: 16px;
}

#myTable td.month {
color: #FFC52E;
align-items: center;
}

.filter-container {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 20%;
}

.filter-title {
font-family: "museo-sans-rounded";
color: #58585B !important;
font-size: 14px;
font-weight: 500px;
line-height: 1.25;
text-align: left;
}

.filter-option {
font-family: "museo-sans-rounded";
color: #58585B !important;
font-size: 13px;
font-weight: 300px;
line-height: 1.5;
text-align: left;
}

.checkbox.style-b {
display: inline-block;
position: relative;
padding-left: 30px;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
margin: 0;
padding-top: 4px;
}

.checkbox.style-b input {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}

.checkbox.style-b input:checked ~ .checkbox__checkmark {
background-color: #fff;
}

.checkbox.style-b input:checked ~ .checkbox__checkmark:after {
opacity: 1;
}

.checkbox.style-b:hover input ~ .checkbox__checkmark {
background-color: #eee;
}

.checkbox.style-b:hover input:checked ~ .checkbox__checkmark {
background-color: #fff;
}

.checkbox.style-b .checkbox__checkmark {
position: absolute;
top: 3px;
left: 0;
height: 20px;
width: 20px;
background-color: #fff;
border: 1px solid #8F8F8F;
transition: background-color 0.25s ease;
border-radius: 4px;
}

.checkbox.style-b .checkbox__checkmark:after {
content: "";
position: absolute;
left: 8px;
top: 3px;
width: 7px;
height: 12px;
border: solid #862B90;
border-width: 0 3px 3px 0;
transform: rotate(45deg);
opacity: 0;
transition: opacity 0.25s ease;
}

.checkbox.style-b .checkbox__body {
color: #212529;
font-feature-settings: 'clig' off, 'liga' off;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px;
}
   
<div id="input">
<div class="filter-container" style="display: flex; flex-direction: column; align-items: flex-start; width: 20%;">
<p>CHECKBOX FILTERS</p>
<p class="filter-title">ID</p>
  <lable><input class="option1" type="checkbox" value="01">01</label>
  <lable><input class="option1" type="checkbox" value="02">02</label>
  <lable><input class="option1" type="checkbox" value="03">03</label>
  <lable><input class="option1" type="checkbox" value="04">04</label>
<p class="filter-title">Name</p>
  <lable><input class="option2" type="checkbox" value="Harry">Harry</label>
  <lable><input class="option2" type="checkbox" value="Ron">Ron</label>
  <lable><input class="option2" type="checkbox" value="Malfoy">Malfoy</label>
  <lable><input class="option2" type="checkbox" value="Hagrid">Hagrid</label>
<p class="filter-title">Month</p>
  <lable><input class="option3" type="checkbox" value="JAN">JAN</label>
  <lable><input class="option3" type="checkbox" value="FEB">FEB</label>
  <lable><input class="option3" type="checkbox" value="MAR">MAR</label>
  <lable><input class="option3" type="checkbox" value="APR">APR</label>
  <lable><input class="option3" type="checkbox" value="MAY">MAY</label>
  <lable><input class="option3" type="checkbox" value="JUN">JUN</label>
<p class="filter-title">House</p>
  <lable><input class="option4" type="checkbox" value="Gryffindor">Gryffindor</label>
  <lable><input class="option4" type="checkbox" value="Slytherin">Slytherin</label>
  <lable><input class="option4" type="checkbox" value="None">None</label>
 <p class="filter-title">Language</p>
  <lable><input class="option4" type="checkbox" value="English">English</label>
  <lable><input class="option4" type="checkbox" value="Spanish">Spanish</label>
  <lable><input class="option4" type="checkbox" value="French">French</label>
</div>              
<p>FILTER TABLE</p>
  
<table id="myTable" class="myTable">
  <thead>
    <tr class="header">
    <th style="width: 3%; text-align: left; padding: 12px;">ID</th>
    <th style="width: 37%; text-align: left; padding: 12px;">Name</th>
    <th style="width: 5%; text-align: center; padding: 12px;">JAN</th>
    <th style="width: 5%; text-align: center; padding: 12px;">FEB</th>
    <th style="width: 5%; text-align: center; padding: 12px;">MAR</th>
    <th style="width: 5%; text-align: center; padding: 12px;">APR</th>
    <th style="width: 5%; text-align: center; padding: 12px;">MAY</th>
    <th style="width: 5%; text-align: center; padding: 12px;">JUN</th>
   </thead>
   <tbody>
      <tr>
        <td class="check1">01</td>
        <td class="check2">Harry</td>
        <td class="check3"></td>
        <td class="check3">FEB</td>
        <td class="check3">MAR</td>
        <td class="check3">APR</td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check4" style="display: none;">Griffindor</td>
        <td class="check5" style="display: none;">Spanish</td>
        <td class="check5" style="display: none;">French</td>
      </tr>
      <tr>
        <td class="check1">01</td>
        <td class="check2">Harry</td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check3">APR</td>
        <td class="check3">MAY</td>
        <td class="check3">JUN</td>
        <td class="check4" style="display: none;">Griffindor</td>
        <td class="check5" style="display: none;">Engligh</td>
        <td class="check5" style="display: none;">Spanish</td>
      </tr>
      <tr>
        <td class="check1">02</td>
        <td class="check2">Ron</td>
        <td class="check3">JAN</td>
        <td class="check3"></td>
        <td class="check3">MAR</td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check4" style="display: none;">Spanish</td>
      </tr>
      <tr>
        <td class="check1">03</td>
        <td class="check2">Hagrid</td>
        <td class="check3">JAN</td>
        <td class="check3">FEB</td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check3">JUN</td>
        <td class="check4" style="display: none;">None</td>
        <td class="check5" style="display: none;">Engligh</td>
      </tr>
      <tr>
        <td class="check1">03</td>
        <td class="check2">Hagrid</td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check3">MAR</td>
        <td class="check3">APR</td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check4" style="display: none;">None</td>
        <td class="check5" style="display: none;">Engligh</td>
      </tr>
      <tr>
        <td class="check1">04</td>
        <td class="check2">Malfoy</td>
        <td class="check3">JAN</td>
        <td class="check3">FEB</td>
        <td class="check3">MAR</td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check3"></td>
        <td class="check4" style="display: none;">Slytherin</td>
        <td class="check5" style="display: none;">Engligh</td>
        <td class="check5" style="display: none;">Spanish</td>
        <td class="check5" style="display: none;">French</td>
      </tr>
    </tbody>
</table>
</div>

javascript filter datatable
1个回答
0
投票

当前逻辑的问题在于,您仅针对刚刚更改的过滤器输入显式地根据每个输入评估列。

  1. 您的规则只需要匹配所选选项中的一个,如果行包含不匹配的单元格,您的代码将隐藏行,因此,如果选择

    JAN
    ,则包含
    FEB
    MAR
    的行以及
    JAN
    都会被过滤掉。

  2. 当前取消选择过滤器的代码不会验证其他列条件,因此取消选择逻辑是因为不明确。

要正确处理可以设置和取消设置的多个条件,您应该重新评估所有条件。但从概念上讲,您应该评估以查看它们是否符合所有条件,而不是评估单个单元格,然后选择返回该行。

在javascript中,我们可以直接访问表格上的行集合,因此我们可以轻松地迭代行,然后比较单元格的值。在这种情况下,我们只需要行值匹配每个选项集中的 1 个选项,它不会尝试匹配每个选项集中的所有选定选项:

function applyFilters() {
  let option1 = getFilter(`input[type='checkbox'].option1`);
  let option2 = getFilter(`input[type='checkbox'].option2`);
  let option3 = getFilter(`input[type='checkbox'].option3`);
  let option4 = getFilter(`input[type='checkbox'].option4`);
  
  let rows = Array.from(document.querySelector('table.myTable').rows);
  rows.forEach(row => {
    // skip the header row
    if (row.getAttribute('class') === 'header') return;
    
    let visible = checkRowFilter(row, '.check1', option1) 
      && checkRowFilter(row, '.check2', option2)
      && checkRowFilter(row, '.check3', option3)
      && checkRowFilter(row, '.check4', option4);
      
    if(visible) 
      row.style = "";
    else 
      row.style = "display:none";
  });

}

/** Get the selected options
 * @param {string} filterQuery - The query selector expression for the checkboxes to evaluate.
 * @returns {Array} of the values for the selected checkboxes
 */
function getFilter(filterQuery) {
  let options = Array.from(document.querySelectorAll(filterQuery));
  return options.filter(option => option.checked == true)
                .map(option => option.value.toLowerCase());
}

/** Evaluate the columns matching the filterCol against the options
 * @param {row} row - The table row to evaluate.
 * @param {string} filterQuery - The query selector expression for the columns to evaluate.
 * @param {Array} options - The array of string values that are valid.
 * @returns {boolean} True if one of the cells matches one of the options
 */
function checkRowFilter(row, filterQuery, options) {
  if (options.length > 0){
        let cells = Array.from(row.querySelectorAll(filterQuery));
        //let values = cells.filter(c => c.innerHTML.trim().length > 0).length;
        let matches = cells.filter(c => options.includes(c.innerHTML.toLowerCase())).length;
        return matches > 0;
  }
  return true;
}

document.querySelectorAll('.option1')
  .forEach(input => input.addEventListener('input', applyFilters));
document.querySelectorAll('.option2')
  .forEach(input => input.addEventListener('input', applyFilters));
document.querySelectorAll('.option3')
  .forEach(input => input.addEventListener('input', applyFilters));
document.querySelectorAll('.option4')
  .forEach(input => input.addEventListener('input', applyFilters));

这是第一个原理方法,虽然它可以发挥作用,但更常见的设计将涉及过滤数据,然后重新渲染数据。这方面的例子超出了本文的范围,但值得您在成为前端开发人员的过程中学习。

© www.soinside.com 2019 - 2024. All rights reserved.