Refactor ValueConverter для динамической фильтрации

Я хотел бы взять следующий 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", либо моему столбцу "имя".

Шаг 1 в рефакторинге, чтобы сделать это повторно используемым, состоял бы в добавлении дополнительного параметра, который может быть массивом строк, имеющих столбцы, которые я хотел бы включить в соответствующую логику ИЛИ.

Если я передам одно значение в массиве, как ["zip"], тогда я просто хочу сопоставить в моем столбце почтового индекса, и не было бы необходимости оператора OR. Если, как в предыдущем случае, я хотел бы сопоставить m, y продуктов, возможно, мой массив будет выглядеть так: ["abbr","name"],

Этот метод выше или, возможно, с определением другого объекта, который знает все столбцы различных объектов, и мы можем использовать его как поиск:

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

Я предвижу это ValueConverter используется в качестве фильтра для многих вещей на моем новом сайте. Было бы лучше использовать его на любом объекте и передать в качестве второго параметра термин "поиск", а в качестве третьего параметра - список имен столбцов, с которыми нужно сопоставить данные, и выполнить его условный поиск с && и / или ||, Вау, это последнее немного сбивало с толку.

Ниже мой взгляд на html-код представления и js для фильтра, я борюсь с тем, как это сделать:

Данные (объект утилиты, который мы фильтруем)

[
  {
    "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!

1 ответ

Вот решение, которое я придумала, так как мне не повезло с построением логического оператора OR с помощью eval ():

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"];
    }
Другие вопросы по тегам