【问题标题】:Filter JavaScript Array Based on Multiple Values基于多个值过滤 JavaScript 数组
【发布时间】:2021-07-06 03:45:35
【问题描述】:

我正在尝试根据多个条件过滤 Javascript 字典。

我尝试执行以下步骤:

  1. 我创建了一个空字典变量

  2. 选择输入元素并获取原始 HTML 节点

  3. 将更改的元素的值保存为变量

  4. 将更改的元素的 id 保存为另一个变量

  5. 有条件地向过滤器对象添加值

    // 1. Create a variable to keep track of all the filters as an object.
     var filters = {};
    
     // 3. Use this function to update the filters. 
     function updateFilters() {
    
     // 4a. Save the element that was changed as a variable.
    
     let changedElement = d3.select(this);
    
     // 4b. Save the value that was changed as a variable.
     let elementValue = changedElement.property("value")
     console.log(elementValue);
    
    
     // 4c. Save the id of the filter that was changed as a variable.
     let filterId = changedElement.attr("id");
     console.log(filterId);
    
    
     // 5. If a filter value was entered then add that filterId and value
     // to the filters list. Otherwise, clear that filter from the filters object.
     if (elementValue != "") {
       filters[filterId] = elementValue;
     }
     else {
       delete filters[filterId];
     }
    
     // 6. Call function to apply all filters and rebuild the table
     filterTable();
    

在下一个函数中,我需要遍历过滤器列表并保留与过滤器值匹配的数据。

// 7. Use this function to filter the table when data is entered.
function filterTable() {
  
  // 8. Set the filtered data to the tableData.
  let filteredData = tableData;

  // 9. Loop through all of the filters and keep any data that
  // matches the filter values


Object.entries(filters).forEach(([filterId, elementValue]) => {
  if (filters[filterId] != "") {
    filteredData = filteredData.filter(entry => entry.datetime === elementValue);

}
if (filters[filterId] != "") {
        filteredData = filteredData.filter(entry => entry.city === elementValue);

    }
if (filters[filterId] != "") {
        filteredData = filteredData.filter(entry => entry.state === elementValue);

    }
if (filters[filterId] != "") {
        filteredData = filteredData.filter(entry => entry.country === elementValue);

    }
if (filters[filterId] != "") {
        filteredData = filteredData.filter(entry => entry.shape === elementValue);

    }


};
// 10. Finally, rebuild the table using the filtered data
    buildTable(filteredData);
  }
  
  // 2. Attach an event to listen for changes to each filter
  d3.selectAll("input").on("change", updateFilters);
  
  
  // Build the table when the page loads
  buildTable(tableData);

    

界面如下:

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!-- <meta http-equiv="X-UA-Compatible" content="IE=edge"> -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/superhero/bootstrap.min.css"> -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css">   
    <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
    <title>UFO Finder</title>
    <link
      rel="stylesheet"
      href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
      integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
      crossorigin="anonymous"
    />
    <link href="https://fonts.googleapis.com/css?family=Ubuntu" rel="stylesheet">
    <link rel="stylesheet" href="static/css/style.css">
    
</head>
<body class="bg-dark">
    <div class="wrapper">
        <nav class="navbar navbar-dark bg-dark navbar-expand-lg">
            <a class="navbar-brand" href="index.html">UFO Sightings</a>
        </nav>
        <div class="jumbotron">
            <h1 class="display-4">The Truth Is Out There</h1>
        </div>
        <div class="container-fluid">
            <div class="row">
                <div class="col-md-4">
                    <h3>UFO Sightings: Fact or Fancy? <small>Ufologists Weigh In</small></h3>
                </div>
                <div class="col-md-8">
                    
                        
                        <p>Some Text</p>

                </div>
                <div class="container-fluid">
                    <div class="row">
                        <div class="col-md-3">
                            <form class="bg-dark">
                                <p>Filter Search</p>
                                <ul class="list-group bg-dark">
                                    <li class="list-group-item bg-dark">
                                        <label for="date">Enter Date</label>
                                        <input type="text" placeholder="1/10/2010" id="datetime"/>
                                    </li>
                                    
                                    <li class="list-group-item bg-dark">
                                        <label for="city">Enter a City</label>
                                        <input type="text" placeholder="roswell" id="city">
                                    </li>
                                    <li class="list-group-item bg-dark">
                                        <label for="state">Enter a State</label>
                                        <input type="text" placeholder="ca" id="state">
                                    </li>
                                    <li class="list-group-item bg-dark">
                                        <label for="Country">Enter a Country</label>
                                        <input type="text" placeholder="us" id="country">
                                    </li>
                                    <li class="list-group-item bg-dark">
                                        <label for="Shape">Enter a Shape</label>
                                        <input type="text" placeholder="crcle" id="shape">
                                    </li>
                                    <!-- <li class="list-group-item bg-dark">
                                        <button id="filter-btn" type="button" class="btn btn-dark" >Clear Table</button>
                                    </li> -->
                                </ul>
                            </form>

                        </div>
                        <div class="col-md-9">
                            <table class="table table-striped">
                                <thead>
                                    <tbody>
                                        <tr>
                                            <th>Date</th>
                                            <th>City</th>
                                            <th>State</th>
                                            <th>Country</th>
                                            <th>Shape</th>
                                            <th>Duration</th>
                                            <th>Comments</th>
                                        </tr>

                                    </tbody>
                                </thead>
                            
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.js"></script>
    <script type="text/javascript" src="./static/js/data.js"></script>
    <script type="text/javascript" src="./static/js/ufo_starterCode.js"></script>
</body>
</html>

data.js

var data = [
  {
    datetime: "1/1/2010",
    city: "benton",
    state: "ar",
    country: "us",
    shape: "circle",
    durationMinutes: "5 mins.",
    comments: "4 bright green circles high in the sky going in circles then one bright green light at my front door."
  },
  {
    datetime: "1/1/2010",
    city: "bonita",
    state: "ca",
    country: "us",
    shape: "light",
    durationMinutes: "13 minutes",
    comments: "Three bright red lights witnessed floating stationary over San Diego New Years Day 2010"
  }
  ];

目标是能够根据用户输入的过滤搜索条件过滤表中的记录。 请注意,我对 Javascript 很陌生。任何帮助表示赞赏。

【问题讨论】:

  • 如果您也能提供实际的 HTML 将会很有帮助,即。 e.图片中显示的内容。这样我们就可以更轻松地演示如何解决您的问题。
  • @CarstenMassmann HTML 添加

标签: javascript d3.js


【解决方案1】:

由于您是 JavaScript 新手,我建议您从基础开始。这意味着:尽量不使用库和框架。在下面的 sn-p 中,我删除了您对 bootstrap、D3、数据表和 jQuery 的引用,因为它们对于解决过滤表的基本问题并不是真正需要的。这也是在 SO 中发布代码的要求。您应该始终尝试提供“MCVE”(一个最低限度的完整且可行的示例)。

我为过滤选择了一个非常基本的概念:看到输入字段直接对应于表的前五列,我应用了遍历所有这些输入的值并将它们与相应的表值进行比较的技巧。这些值是通过对表行 (&lt;tr&gt;) 执行 forEach() 循环然后确保我得到每行的前五个 &lt;td&gt;s ([...tr.children].slice(0,5)) 的“正匹配”来找到的。文本比较是在每个inp.value 的小写版本(存储在vals[I] 中)和对应的td.textContent 之间进行的,但前提是vals[i] 不为空(否则返回正匹配,作为空vals[i] 表示该列没有过滤)。因此,如果所有五列(.every()-loop)都满足“匹配”条件,则当前&lt;tr&gt;.style.display 属性设置为"",否则设置为"none"

const data = [
  { datetime: "1/1/2010", city: "benton", state: "ar", country: "us", shape: "circle", durationMinutes: "5 mins.",
    comments: "4 bright green circles high in the sky going in circles then one bright green light at my front door." },
  { datetime: "1/1/2010", city: "bonita", state: "ca", country: "us", shape: "light", durationMinutes: "13 minutes",
    comments: "Three bright red lights witnessed floating stationary over San Diego New Years Day 2010" },
  { datetime: "1/13/2010", city: "Bonita", state: "ca", country: "us", shape: "square", durationMinutes: "3 minutes",
    comments: "Early in January we saw a blue square appear right out of nowhere." }];

// fill table:
const tb=document.querySelector("table tbody");
tb.innerHTML=
  data.map(r=>"<tr><td>"+Object.values(r).join("</td><td>")+"</td></td>").join("\n");
// filter table:
const inps=[...document.querySelectorAll("ul input")];
document.querySelector("ul").addEventListener("input",ev=>{
  const vals=inps.map(inp=>inp.value.toLowerCase());
  // filter table according to content of first 5 columns:
  [...tb.children].forEach(tr=>  // check for every table record:
    tr.style.display=[...tr.children].slice(0,5).every((td,i)=> 
      vals[i]==="" || td.textContent.toLowerCase().includes(vals[i])
    ) ? "" : "none" 
    // show record if vals[i]==="" or if vals[i] is part of the corresponding column contents
  )
})
.table-striped tbody tr:nth-child(odd) {background-color:#ddd}
<div class="wrapper">
  <div class="jumbotron">
    <h1 class="display-4">The Truth Is Out There</h1>
  </div>
  <div class="container-fluid">
    <div class="row">
      <div class="container-fluid">
        <div class="row">
          <div class="col-md-3">
            <form class="bg-dark">
              <p>Filter Search</p>
              <ul class="list-group bg-dark">
                <li class="list-group-item bg-dark">
                  <label for="date">Enter Date</label>
                  <input type="text" placeholder="1/10/2010" id="datetime" />
                </li>
                <li class="list-group-item bg-dark">
                  <label for="city">Enter a City</label>
                  <input type="text" placeholder="roswell" id="city">
                </li>
                <li class="list-group-item bg-dark">
                  <label for="state">Enter a State</label>
                  <input type="text" placeholder="ca" id="state">
                </li>
                <li class="list-group-item bg-dark">
                  <label for="Country">Enter a Country</label>
                  <input type="text" placeholder="us" id="country">
                </li>
                <li class="list-group-item bg-dark">
                  <label for="Shape">Enter a Shape</label>
                  <input type="text" placeholder="crcle" id="shape">
                </li>
                <li class="list-group-item bg-dark">
                  <button id="filter-btn" type="button" class="btn btn-dark">Clear Table</button>
                </li>
              </ul>
            </form>

          </div>
          <div class="col-md-9">
            <table class="table table-striped">
              <thead>              
                <tr>
                  <th>Date</th>
                  <th>City</th>
                  <th>State</th>
                  <th>Country</th>
                  <th>Shape</th>
                  <th>Duration</th>
                  <th>Comments</th>
                </tr>
              </thead>
              <tbody></tbody>
            </table>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

【讨论】:

  • 感谢您的详细解释。我同意你保持基本的观点。但是请注意,这个问题是大型数据分析项目任务的一小部分,需要使用 Javascript、D3.js 来处理这个“小部分”。再次感谢您的宝贵时间。
【解决方案2】:

原始代码在循环过滤器时试图过滤数据对象;下面的代码实现在遍历数据对象的同时遍历过滤器对象。
由于我的行数总是多于过滤器,因此我只运行一次 .filter 方法,而不是像最初尝试那样运行每个过滤器。

// 9. Loop through all of the filters and keep any data that matches the filter values
let filteredData = tableData.filter((obj) => {
    for(filterId in filters) {
        if(obj[filterId] !== filters[filterId]) {
          return false;
        }
    }
    return true;
  });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 2020-07-04
    • 2021-10-08
    • 2019-07-29
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多