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"];
}