数组过滤无法按预期工作

时间:2016-05-28 10:33:46

标签: javascript arrays

我有一系列物品,我想根据它们的大小,颜色和衣领过滤它们。

每当我取消选中一个复选框时,一切都按预期工作,但当我再次重新检查它时,它会带回不需要的对象。



var DATABASE = [
    {id:0o1, size: "XL",  color:"red",    collar: "v-neck"},
    {id:0o2, size: "S",   color:"blue",   collar: "regular"},
    {id:0o3, size: "XXL", color:"red",    collar: "scoop"},
    {id:0o4, size: "L",   color:"green",  collar: "v-neck"},
    {id:0o5, size: "XL",  color:"blue",   collar: "turtle-neck"},
    {id:0o6, size: "L",   color:"red",    collar: "v-neck"}
];


window.onload = function () {

    var vNeckCollarCheckbox = document.querySelector('#vneck-collar-checkbox');
    var xlSizeCheckbox = document.querySelector('#xl-size-checkbox');
    var redColorCheckbox = document.querySelector('#red-color-checkbox');

    var div = document.querySelector('div');


    var DB = DATABASE;


    function filterByVneckCollar() {
        let vNeckCollar = DATABASE.filter(function (item) {
            return item.collar === "v-neck";
        });
        if(!vNeckCollarCheckbox.checked){
            DB = DB.filter(function (i) {
                return vNeckCollar.indexOf(i) < 0;
            });
            div.innerHTML = JSON.stringify(DB);
        }
        else{
            DB = DB.concat(vNeckCollar);
            div.innerHTML = JSON.stringify(DB);
        }
    }

    function filterByXlSize() {
        let xlSize = DATABASE.filter(function (item) {
            return item.size === "XL";
        });
        if(!xlSizeCheckbox.checked){
            DB = DB.filter(function (i) {
                return xlSize.indexOf(i) < 0;
            });
            div.innerHTML = JSON.stringify(DB);
        }
        else{
            DB = DB.concat(xlSize);
            div.innerHTML = JSON.stringify(DB);
        }
    }

    function filterByRedColor() {
        let redColor = DATABASE.filter(function (item) {
            return item.color === "red";
        });
        if(!redColorCheckbox.checked){
            DB = DB.filter(function (i) {
                return redColor.indexOf(i) < 0;
            });
            div.innerHTML = JSON.stringify(DB);
        }
        else{
            DB = DB.concat(redColor);
            div.innerHTML = JSON.stringify(DB);
        }

    }


    div.innerHTML = JSON.stringify(DB);

    vNeckCollarCheckbox.addEventListener('change', filterByVneckCollar);
    xlSizeCheckbox.addEventListener('change', filterByXlSize);
    redColorCheckbox.addEventListener('change', filterByRedColor);

};
&#13;
<html>
<head>
    <script src="js.js"></script>
</head>

<body>
<form action="#">

    <input type="checkbox" id="vneck-collar-checkbox" checked>
    <label for="vneck-collar-checkbox">V-neck collar</label>
    <br>
    <input type="checkbox" id="xl-size-checkbox" checked>
    <label for="xl-size-checkbox">XL size</label>
    <br>
    <input type="checkbox" id="red-color-checkbox" checked>
    <label for="red-color-checkbox">Red color</label>

</form>
<div></div>
</body>
</html>
&#13;
&#13;
&#13;

试试这个:

  1. 取消选中&#34;红色&#34;
  2. 取消选中&#34; XL尺寸&#34;
  3. 检查&#34; XL尺寸&#34;
  4. 你会看到包含&#34;颜色的对象:红色&#34;出现。

    我知道问题出现在 DB = DB.concat(xxxxx); of else {}声明中,但我不知道如何实现所需的输出。

    赞赏实现此类过滤器的任何其他解决方案/概念。

5 个答案:

答案 0 :(得分:2)

只需使用您需要的规则组合过滤DATABASE一次。

我已经为你提供了一个更复杂的功能JSDoc,我制作了通用的,所以也可以用于其他的东西

/**
 * @callback FilterRuleTest
 * @param {Object} obj The target Object
 * @returns {Boolean} Whether obj passed the test
 */

/**
 * @typedef {Object} FilterRule
 * @property {String} [key] A property key to find on the target
 * @property {String} [value] The value assigned to the key of the target
 * @property {FilterRuleTest} [test] A function to run on target, return bool
 */

/** Filters an Array of Objects
 * @param {[Object]} arrayOfObjects The Array of Objects to filter
 * @param {[FilterRule]} arrayOfRules The Array of Objects to filter with
 * @param {Boolean} [invert] Return the opposite of the rules
 * @param {Boolean} [emptyRulePasses] Default behaviour of empty rule
 * @returns {[Object]} The filtered result
 */
function objFilter(arrayOfObjects, arrayOfRules, invert = false, emptyRulePasses = false) {
    return arrayOfObjects.filter(obj => {
        return invert !== arrayOfRules.every(rule => {
            if ('key' in rule) {
                if ('value' in rule)
                    return obj[rule.key] === obj[rule.value];
                return rule.key in obj;
            }
            if ('test' in rule) {
                return rule.test(obj);
            }
            return emptyRulePasses;
        });
    });
}

function createFilterRules(collar, size, color) {
    let rules = [];
    if (collar) rules.push({key: 'collar', value: collar});
    if (size) rules.push({key: 'size', value: size});
    if (color) rules.push({key: 'color', value: color});
    return rules;
}

const vNeckCollarCheckbox = document.querySelector('#vneck-collar-checkbox');
const xlSizeCheckbox = document.querySelector('#xl-size-checkbox');
const redColorCheckbox = document.querySelector('#red-color-checkbox');
const div = document.querySelector('div');

function filterClothes(db) {
    return objFilter(
        db,
        createFilterRules(
            vNeckCollarCheckbox.checked ? 'v-neck' : null,
            xlSizeCheckbox.checked ? 'XL' : null,
            redColorCheckbox.checked ? 'red' : null
        )
    );
}

function clothesHandle() {
    div.innerHTML = JSON.stringify(filterClothes(DATABASE));
}

vNeckCollarCheckbox.addEventListener('change', clothesHandle);
xlSizeCheckbox.addEventListener('change', clothesHandle);
redColorCheckbox.addEventListener('change', clothesHandle);

答案 1 :(得分:2)

问题是您的过滤器功能以完整集开始,并仅基于其中一个复选框值过滤掉。

而是创建一个一对一的过滤器。

您还可以以简洁的方式编写过滤条件:设置复选框,或者应用条件。这可以用布尔||运算符表示。

最后,我建议使用DOMContentLoaded事件而不是load事件,因为它会更快地触发,同时仍保证可以访问DOM元素。

var DATABASE = [
    {id:0o1, size: "XL",  color:"red",    collar: "v-neck"},
    {id:0o2, size: "S",   color:"blue",   collar: "regular"},
    {id:0o3, size: "XXL", color:"red",    collar: "scoop"},
    {id:0o4, size: "L",   color:"green",  collar: "v-neck"},
    {id:0o5, size: "XL",  color:"blue",   collar: "turtle-neck"},
    {id:0o6, size: "L",   color:"red",    collar: "v-neck"}
];

document.addEventListener("DOMContentLoaded", function () {
    var vNeckCollarCheckbox = document.querySelector('#vneck-collar-checkbox');
    var xlSizeCheckbox = document.querySelector('#xl-size-checkbox');
    var redColorCheckbox = document.querySelector('#red-color-checkbox');
    var div = document.querySelector('div');

    function applyFilter() {
        div.innerHTML = JSON.stringify(DATABASE.filter(function (item) {
            return (vNeckCollarCheckbox.checked || item.collar !== "v-neck") &&
                   (xlSizeCheckbox.checked      || item.size !== "XL") &&
                   (redColorCheckbox.checked    || item.color !== "red");
        }));
    }

    vNeckCollarCheckbox.addEventListener('change', applyFilter);
    xlSizeCheckbox.addEventListener('change', applyFilter);
    redColorCheckbox.addEventListener('change', applyFilter);
    
    applyFilter();
});              
<form action="#">
    <input type="checkbox" id="vneck-collar-checkbox" checked>
    <label for="vneck-collar-checkbox">V-neck collar</label>
    <br>
    <input type="checkbox" id="xl-size-checkbox" checked>
    <label for="xl-size-checkbox">XL size</label>
    <br>
    <input type="checkbox" id="red-color-checkbox" checked>
    <label for="red-color-checkbox">Red color</label>
</form>
<div></div>

答案 2 :(得分:1)

您的复选框每个都会为全局过滤器提供单独的部分。如果取消选中复选框,1。您的全局过滤器将被修改,2。您选择的数据是使用修改后的过滤器过滤数据库的结果。

关于您的全球&#39; filter:您可以将它实现为单个Array.filter()回调,如果应该根据任何复选框过滤给定元素,则返回true,或者您可以将调用链接到Array.filter()根据单个复选框的回调过滤元素。

不需要连接。

答案 3 :(得分:1)

每当其中一个过滤器发生更改时,您可以按所有属性过滤基础数组。

function applyFilters(){

    curr_db = DB;

    if ( ! vNeckCollarCheckbox.checked) {
        curr_db = filterByVneckCollar(curr_db);
    }
    if ( ! xlSizeCheckbox.checked) {
        curr_db = filterByXlSize(curr_db);
    }
    if ( ! redColorCheckbox.checked) {
        curr_db = filterByRedColor(curr_db);
    }

    div.innerHTML = JSON.stringify(curr_db);
}

vNeckCollarCheckbox.addEventListener('change', applyFilters);
xlSizeCheckbox.addEventListener('change', applyFilters);
redColorCheckbox.addEventListener('change', applyFilters);

然后使用过滤器功能仅删除不需要的项目。

function filterByRedColor(curr_db) {
    return curr_db.filter(function(){
        return item.color != "red";
    });
}

...

答案 4 :(得分:1)

只需一个过滤器功能就可以解决这个问题,每当你逐项过滤检查你的过滤器是否满足复选框的每个条件时......如果是,那么通过在过滤器函数中返回true来接受它。 。否则为该项目返回false将不会在选择数据库中显示该项目......我希望这可以澄清您的疑问......

var selection = [];

var vNeckCollarCheckbox = document.querySelector('#vneck-collar-checkbox').checked;
var xlSizeCheckbox = document.querySelector('#xl-size-checkbox').checked;
var redColorCheckbox = document.querySelector('#red-color-checkbox').checked;

selection = DATABASE.filter(function (item) {
    // Write all condition which will fail for the current data here and return false, every condition passes it will send true by default at the end
    if(vNeckCollarCheckbox) {
        if(item.collar != "v-neck") {
            return false;
        }
    }

    if(xlSizeCheckbox) {
        if(item.size != "XL") {
            return false;
        }
    }

    if(redColorCheckbox) {
        if(item.color != "red") {
            return false;
        }
    }

    return true;
});