重构ValueConverter以动态过滤

Refactor ValueConverter to filter dynamically

本文关键字:过滤 动态 ValueConverter 重构      更新时间:2023-09-26

我想采用以下ValueConverter并使其可用于许多视图。

export class ProductFilterValueConverter {
    toView(array, value) {
        var regex = new RegExp(value, 'gi');
        var matcher = item =>
            item.abbr.match(regex) || item.name.match(regex);
        return array.filter(
            matcher
        );
    }
}

上面的过滤器从文本字段中获取一个值,并匹配我的'abbr'列或'name'列。

为了使这个可重用,重构的第一步是添加一个额外的参数,这个参数可能是一个字符串数组,其中包含我想要在匹配的OR逻辑中包含的列。

如果我在数组中传递一个值,如["zip"],那么我只想匹配我的zipcode列,并且不需要OR操作符。如果像上面的例子一样,我想匹配m,y个乘积,也许我的数组是这样的:["abbr","name"]

上面的方法或者可能有另一个对象定义,知道所有不同的对象列,我们可以使用它作为查找:

var lookup = {
    products: ["abbr","name"],
    zipcodes: ["zip"],
    offices: ["city", "state", "zipcode"]
}

我预见这个ValueConverter被用作我的新网站的许多东西的过滤器。最好在任何对象上使用它,并将搜索词作为第二个参数传递,将要匹配的列名列表作为第三个参数传递,并使用&&和/或||进行有条件搜索。哇,最后一点让人困惑。

下面是我的镜头到目前为止在视图的html代码和js的过滤器,我正在努力如何做到这一点:

Data(我们要过滤的实用程序对象)

[
  {
    "id": 1,
    "utilityName": "Big Valley",
    "abbr": "Big Valley",
    "city": "Big Bear Lake"
  },
  {
    "id": 2,
    "utilityName": "Pac Electric",
    "abbr": "PE",
    "city": "Los Angelas"
  }
]

GenericFilter.js

export class GenericFilterValueConverter {
    toView(array, value, cols) {
        var columns = cols;
        var matchLogic = "item => {";
        var regex = new RegExp(value, 'gi');
        //debugger;
        for (var i = 1; i <= columns.length; i++) {
            matchLogic += "item." + columns[i] + ".match(regex)";
            matchLogic += (i < columns.length) ? " || " : "";
            matchLogic += (i === columns.length ? "}" : "");
        }
        var matcher = eval(matchLogic);
        return array.filter(
            matcher
        );
    }
}

view.js

export class Utilities { 
    constructor(...) {
    //below the definedColumns are defined in the js module
    this.definedColumns = ["abbr","utilityName"];
}

view.html

<template>
    <!--<require from="./officeFilter"></require>-->
    <require from="../services/genericFilter"></require>
    <input type="text" name="searchValue" value.bind="searchValue" />
    <div class="grid" repeat.for="office of offices | genericFilter:searchValue:definedColumns">
            <!--MORE HTML HERE TO RENDER GRID-->
        </div>
    </div>
</template>

目前我没有得到一个JavaScript错误,但我的过滤器不再工作。我在我的页面上有零结果,如果ValueConverter第一次运行,array.filter可能过滤掉了所有的结果?

使用eval的想法显然不是最好的,我在下面给出的答案并没有使用邪恶的eval!

这是我想出的解决方案,因为我没有幸运地用eval()构建逻辑OR语句:

GenericFilter.js

    export class GenericFilterValueConverter {
    toView(array, value, cols, showResults=false) {
        if (!value) {
            return showResults ?  array :  [];
        };
        var filteredArray = array.filter(
            function(objArray) {
                for (var col in objArray) {
                    if (objArray.hasOwnProperty(col)) {
                        if (cols.indexOf(col) != -1 && objArray[col].toLowerCase().indexOf(value.toLowerCase()) != -1) {
                            return true;
                        }
                    }
                };
                return false;
            });
        return filteredArray;
    }
}

view.html

<template>
    <require from="../services/genericFilter"></require>
    <input type="text" name="searchValue" value.bind="searchValue"/>
        <div  class="grid" repeat.for="utility of utilities | genericFilter:searchValue:definedColumns:true">
                <!--template repeats for each utility-->
            </div>
        </div>
    </div>
</template>

view.js

 export class Utilities {
    constructor(utilityNameData, router) {
        this.data = utilityNameData;
        this.router = router;
        this.utilities = [];
        //...
        this.definedColumns = ["abbr","utilityName"];
    }