javascript - React中具有多个值的多个列表框搜索数组过滤器
问题描述
我正在从 O365 REST 调用中填充一个对象,然后使用 SPfx FluentUI 详细信息列表应用程序中的多选下拉菜单进行过滤。我的代码是附加来自每个下拉列表的任何值的结果,而不是缩小结果以满足所有过滤条件。
示例 Codepen:https ://codepen.io/detailcode/pen/VwmdZoo
<!DOCTYPE html><html><body>
<select id="lstTitle" multiple size="4">
<option value="" selected>(Select Multi Values)</option>
<option value="Apple">Apple</option>
<option value="Pear">Pear</option>
<option value="Grape">Grape</option>
<option value="Banana">Banana</option>
<option value="Beet">Beet</option>
<option value="Grapefruit">Grapefruit</option>
<option value="Lemon">Lemon</option>
</select>
<select id="lstColor" multiple size="4">
<option value="" selected>(Select Multi Values)</option>
<option value="Red">Red</option>
<option value="Green">Green</option>
<option value="Yellow">Yellow</option>
</select>
<select id="lstTaste" multiple size="4">
<option value="" selected>(Select Multi Values)</option>
<option value="Sweet">Sweet</option>
<option value="Sour">Sour</option>
<option value="Bitter">Bitter</option>
</select>
<input id="butFilter" type="button" value="Filter" onclick="butFilter_Click()" />
<p>All Results:</p>
<div id="cssResults1" style="padding:3px 10px;border:1px solid #000;">No data</div>
<p>Single Select Result:</p>
<div id="cssResults2" style="padding:3px 10px;border:1px solid #000;">No data</div>
<p>Multi Select Result: (Selecting Apple, Pear, Grape, Red, Green, Sweet, Sour) <strong>Desired result being records 1, 2, 4, 5, 6</strong></p>
<div id="cssResults3" style="padding:3px 10px;border:1px solid #000;">No data</div>
<script>
let data = [
{ 'id': 1, 'title': 'Apple', 'color': 'Red', 'taste': 'Sweet', },
{ 'id': 2, 'title': 'Apple', 'color': 'Green', 'taste': 'Sour', },
{ 'id': 3, 'title': 'Apple', 'color': 'Yellow', 'taste': 'Sweet', },
{ 'id': 4, 'title': 'Pear', 'color': 'Green', 'taste': 'Sweet', },
{ 'id': 5, 'title': 'Grape', 'color': 'Red', 'taste': 'Sweet', },
{ 'id': 6, 'title': 'Grape', 'color': 'Green', 'taste': 'Sour', },
{ 'id': 7, 'title': 'Banana', 'color': 'Yellow', 'taste': 'Sweet', },
{ 'id': 8, 'title': 'Beet', 'color': 'Red', 'taste': 'Bitter', },
{ 'id': 9, 'title': 'Grapefruit', 'color': 'Yellow', 'taste': 'Bitter', },
{ 'id': 10, 'title': 'Lemon', 'color': 'Yellow', 'taste': 'Sour', },
]
//var result1 = data.filter(e => e.color == 'Yellow' && e.taste == 'Sweet');
console.log(data);
document.getElementById("cssResults1").innerHTML = "<p>" + JSON.stringify(data) + "<p>";
function butFilter_Click() {
var result2 = data.filter(e =>
e.title == (document.getElementById("lstTitle").value != "" ? document.getElementById("lstTitle").value : e.title) &&
e.color == (document.getElementById("lstColor").value != "" ? document.getElementById("lstColor").value : e.color) &&
e.taste == (document.getElementById("lstTaste").value != "" ? document.getElementById("lstTaste").value : e.taste));
document.getElementById("cssResults2").innerHTML = "<p>" + JSON.stringify(result2) + "<p>";
console.log(result2); // LOG SINGLE SELECT RESULT
const valTitle = Array.apply(null, document.getElementById("lstTitle").options).filter(option => option.selected).map(option => option.value);
const valColor = Array.apply(null, document.getElementById("lstColor").options).filter(option => option.selected).map(option => option.value);
const valTaste = Array.apply(null, document.getElementById("lstTaste").options).filter(option => option.selected).map(option => option.value);
console.log(valTitle); // LOG lstTitle MULTI VALUES
console.log(valColor); // LOG lstColor MULTI VALUES
console.log(valTaste); // LOG lstTaste MULTI VALUES
// INCLUSIVELY ADDS TO RESULT VERSUS MATCHING ALL KEY VALUES
let tempContat = [];
let temp;
for(var i = 0; i < valTitle.length; i++) {
temp = data.filter(e => e.title == (valTitle[i] != "" ? valTitle[i] : e.title))
tempContat = tempContat.concat(temp);
}
for(var i = 0; i < valColor.length; i++) {
temp = data.filter(e => e.color == (valColor[i] != "" ? valColor[i] : e.color))
tempContat = tempContat.concat(temp);
}
for(var i = 0; i < valTaste.length; i++) {
temp = data.filter(e => e.taste == (valTaste[i] != "" ? valTaste[i] : e.taste))
tempContat = tempContat.concat(temp);
}
var result3 = tempContat;
document.getElementById("cssResults3").innerHTML = "<p>" + JSON.stringify(result3) + "<p>";
console.log(result3); // LOG MULTI SELECT RESULT
}
</script>
</body></html>
更新:如何过滤对象以在最终结果中包含(与结果3相反)?选择水果(苹果、梨、葡萄)、颜色(红色、绿色)和口味(甜、酸)时,预期结果应为 ID 1、2、4、5 和 6。如果每个搜索条件不符合,它应该像在搜索引擎过滤器中一样被排除。
解决方案
问题是您拥有的每个 for 循环都独立于用于过滤掉对象的谓词。要解决此问题,您需要将所有谓词置于同一范围内,以便由于当前谓词的范围而不会添加应该省略的内容。例如:
for(var i = 0; i < valTitle.length; i++) {
// this predicate will remove all things relating to titles
temp = data.filter(e => e.title == (valTitle[i] != "" ? valTitle[i] : e.title))
tempContat = tempContat.concat(temp);
}
// these for loops are independent and all re-use the same 'data' so its possible for the previous loop's omitted objects to be filtered in again
// because the filter constraint in the next for loop doesn't include the previous ones constraints
for(var i = 0; i < valColor.length; i++) {
// this filter's predicate is unaware that 'e.title' of some type should be omitted, it only knows to filter out colors of some type `valColor[i]`
temp = data.filter(e => e.color == (valColor[i] != "" ? valColor[i] : e.color))
// here some titles that should be omitted are added in because it matched on the color from the predicate above
tempContat = tempContat.concat(temp);
}
for(var i = 0; i < valTaste.length; i++) {
temp = data.filter(e => e.taste == (valTaste[i] != "" ? valTaste[i] : e.taste))
tempContat = tempContat.concat(temp);
}
正因为如此,它也可以添加重复项,因为过滤器是基于data
永远不会更改的,并且是要过滤的所有可用内容。
要解决此问题,您需要组合谓词,下面我通过使用 1 个过滤器并将谓词放在一起来做到这一点。
const result3 = data.filter((e) => {
// element must have at least one of these titles to be filtered in
if (!valTitle.some((title) => e.title == (title != "" ? title : e.title))) {
return false;
}
// and
// element must have at least one of these colors to be filtered in
if (!valColor.some((color) => e.color == (color != "" ? color : e.color))) {
return false;
}
// and
// element must have at least one of these tastes to be filtered in
if (!valTaste.some((taste) => e.taste == (taste != "" ? taste : e.taste))) {
return false;
}
return true;
});
您可以执行与上述解决方案类似的操作。
推荐阅读
- php - 如何将查询结果插入php中的数组并在另一个数组中检查它们
- https - HTTPS 的 GnuTLS 问题
- symfony - 设置数据未映射字段不起作用
- html - 仅适用于 chrome 的滚动 flex 布局
- java - 为什么在尝试对此图进行 DFS 以查找强连接组件时会出现 StackOverFlowError?
- c++ - 尝试在 C++ 中捕获 - 创建了多少对象
- sql - 消息 4104,级别 16,状态 1,行 30 无法绑定多部分标识符“Describe.Product_ID”
- c++ - 将参数传递给另一个可变参数函数
- angularjs - Angular Schema Form - “必需”不工作选择和复选框字段
- scala - 用于 Spark 数据帧的具有 partitionBy 的窗口函数不起作用