使用一个管道角度 2 过滤多个列
Posted
技术标签:
【中文标题】使用一个管道角度 2 过滤多个列【英文标题】:Filter on multiple columns using one pipe angular 2 【发布时间】:2017-05-31 01:35:56 【问题描述】:我正在尝试仅使用一个Pipe
基于多列过滤Array
数据。现在,它过滤第一列值。请检查我下面的代码并帮助我解决这个问题。
我的代码:
@Pipe( name: "dataFilter", pure: false )
export class DataFilterPipe implements PipeTransform
transform(value: Array<any>, filter: any[])
if (!filter)
return value;
else if (value)
return value.filter(item =>
for (var i = 0; i < filter.length; i++)
if (filter[i][1] == undefined)
return true;
else if ((typeof item[filter[i][0]] === 'string' || item[filter[i][0]] instanceof String) &&
(item[filter[i][0]].toLowerCase().indexOf(filter[i][1]) !== -1))
return true;
return false;
);
我正在传递像dataFilter : [['column1',value1],['column2',value2],['column3',value3]]
这样的数据。
【问题讨论】:
您能提供一个示例值吗?是否在表格上:[col1:"col1",col2:"col2",col3:"col3",...,]
?
【参考方案1】:
html 标记:
*ngFor="let item of _items | filtername: column1: searchtext, column2: searchtext : false"
变换函数:
transform(items: any, filter: any, isAndOperationBwCol: bool): any
if (filter && Array.isArray(items))
let filterKeys = Object.keys(filter);
if (isAndOperationBwCol)
return items.filter(item =>
filterKeys.reduce((memo, keyName) =>
(memo && new RegExp(filter[keyName], 'gi').test(item[keyName])) || filter[keyName] === "", true));
else
return items.filter(item =>
return filterKeys.some((keyName) =>
console.log(keyName);
return new RegExp(filter[keyName], 'gi').test(item[keyName]) || filter[keyName] === "";
);
);
else
return items;
参考:https://long2know.com/2017/04/angular-pipes-filtering-on-multiple-keys/
【讨论】:
【参考方案2】:这是一个使用作为多列过滤器传递的对象的解决方案。我发现它比传递二维数组更方便:
@Pipe(
name: 'filter'
)
export class FilterPipe implements PipeTransform
transform(items: Array<any>, filter: [key: string]: any ): Array<any>
return items.filter(item =>
const notMatchingField = Object.keys(filter)
.find(key => item[key] !== filter[key]);
return !notMatchingField; // true if matches all fields
);
拥有一个包含多列的对象数组:
this.people = [
name: 'John', age: 27, sex: 'male',
name: 'Lara', age: 21, sex: 'female',
name: 'Rick', age: 29, sex: 'male',
name: 'Eva', age: 27, sex: 'female',
name: 'Mike', age: 27, sex: 'male'
];
还有一个过滤器:
this.peopleFilter = age: 27, sex: 'male';
像这样使用它:
<div *ngFor="let person of people | filter: peopleFilter;"></div>
因此,有两个人符合我们的条件:John 和 Mike。
这里是工作插件:Multiple columns filter pipe demo.
【讨论】:
当我使用它时,它不显示任何数据,即使我输入值时也没有得到任何数据。 这里是工作插件:plnkr.co/edit/e0PCIsqXumbXe6mAUWBI?p=preview 谢谢。我将您的帖子标记为答案,但如果没有值(那么它应该返回所有值)或值是任何人输入的数字怎么办? 谢谢!如果没有提供值,假设我们的过滤器是 ,那么所有项目都将被返回,否则它与提供的确切值匹配,这很好,因为例如,可能存在我们想要过滤具有 null 或未定义的字段。 Ofc,这是一个概念,可以根据情况调整解决方案。 谢谢@SeidMehmedovic。调整为过滤同一键的多个值。 Plunker 链接 - plnkr.co/edit/bUeQHzWhDp1qnrvj3tl4【参考方案3】:我必须有一个可以同时按特定属性值和名为“All”的通用值进行过滤的管道。用户可以通过从下拉列表中选择它们来动态调整这些过滤器(因此使用效率较低的pure: false
配置)。
在组件中(必须默认为“全部”)
public filters = status: "All", condition: "All", other: "All" ;
在模板中
<div *ngFor="let item of items | filter:filters">
@Pipe(
name: 'filter',
pure: false
)
export class FilterPipe implements PipeTransform
transform(items: Array<any>, filter: [key: string]: any ): Array<any>
return items.filter(item =>
let matches = Object.keys(filter).every(f =>
return filter[f] === 'All' || item[f] == filter[f];
)
return matches;
)
【讨论】:
【参考方案4】:这是我对 Angular 8 所做的:
目标:从给定关键字的项目列表中搜索多个属性,例如“Property1”和“Property2”:
app.module.ts:
......
import MyFilterPipe from './shared/pipes/my-filter.pipe';
@NgModule(
declarations: [
...
MyFilterPipe
],
imports: [
...
],
providers: [],
bootstrap: [AppComponent]
)
export class AppModule
管道:content-filter.pipe.ts
import Pipe, PipeTransform from '@angular/core';
@Pipe(
name: 'myFilter'
)
export class MyFilterPipe implements PipeTransform
transform(items: any[], keyword: any, properties: string[]): any[]
if (!items) return [];
if (!keyword) return items;
debugger;
return items.filter(item =>
var itemFound: Boolean;
for (let i = 0; i < properties.length; i++)
if (item[properties[i]].toLowerCase().indexOf(keyword.toLowerCase()) !== -1)
itemFound = true;
break;
return itemFound;
);
组件:
<input type="search" class="form-control filter-list-input" placeholder="Filter"
aria-label="Filter" name="search" [(ngModel)]="searchText" >
<div *ngFor="let itemof myItems | myFilter:searchText:['Property1', 'Property2']; let i = index">...
</div>
component.ts:
export class MyListComponent implements OnInit
...
searchText: string;
【讨论】:
【参考方案5】:您可以看到整个工作 ArrayFilterPipe.ts @http://typescript.io/uN29xRdF1Ag 或 typescriptlang.org此外,我还附上了打字稿的编译 JS,以便于查看您想要的输出。 如果需要注释代码,请告诉我...
FYI 选项数组在执行过滤器之前被转换为对象,因为数组感觉很舒服。
/* yours */
var option = [['column1',value1],['column2',value2],['column3',value3]];
/* mine */
var option = column1: 'value1', column2: 'value2', column3: 'value3' ;
static _arrayToObject(value: Array<Array<any>>): any
return (ArrayFilterPipe._isUndefined(value) || value == null)
? value
: value.reduce((result, current) =>
result[current[0]] = current[1];
return result;
, );
您还可以通过从https://github.com/angular/angular.js/blob/master/src/ng/filter/filter.js 获得一些灵感来构建类似于 angular 1.x 的数组/对象过滤器
var ArrayFilterPipe = (function ()
function ArrayFilterPipe()
ArrayFilterPipe._isOfType = function (value, type)
return typeof (value) === type;
;
ArrayFilterPipe._isUndefined = function (value)
return ArrayFilterPipe._isOfType(value, ArrayFilterPipe.TYPES.UNDEFINED);
;
ArrayFilterPipe._isObject = function (value)
return ArrayFilterPipe._isOfType(value, ArrayFilterPipe.TYPES.OBJECT);
;
ArrayFilterPipe._isOrHasMatch = function (value, target)
return ArrayFilterPipe._isOfType(value, ArrayFilterPipe.TYPES.STRING) || ArrayFilterPipe._isOfType(target, ArrayFilterPipe.TYPES.STRING)
? value.toString().toLowerCase().indexOf(target.toString().toLowerCase()) >= 0
: value == target;
;
ArrayFilterPipe._hasOptions = function (value, options)
return (ArrayFilterPipe._isUndefined(value) || ArrayFilterPipe._isUndefined(options) ? (ArrayFilterPipe._isUndefined(value) && ArrayFilterPipe._isUndefined(options))
: (value === null || options == null) ? (value === null && options == null)
: (Array.isArray(value) || Array.isArray(options)) ? false
: ArrayFilterPipe._isObject(value) ?
(ArrayFilterPipe._isObject(options)
? Object.keys(options).every(function (key) return value.hasOwnProperty(key) && ArrayFilterPipe._isOrHasMatch(value[key], options[key]); )
: Object.values(value).some(function (val) return ArrayFilterPipe._isOrHasMatch(val, options); ))
: !ArrayFilterPipe._isObject(value) ?
(!ArrayFilterPipe._isObject(options)
? ArrayFilterPipe._isOrHasMatch(value, options)
: false)
: false);
;
ArrayFilterPipe._arrayToObject = function (value)
return (ArrayFilterPipe._isUndefined(value) || value == null) ? value : value.reduce(function (result, current)
result[current[0]] = current[1];
return result;
, );
;
ArrayFilterPipe.prototype.transform = function (value, options)
if (!value || !Array.isArray(value) || ArrayFilterPipe._isUndefined(options) || options === null)
return value;
options = Array.isArray(options) ? ArrayFilterPipe._arrayToObject(options) : options;
return value.filter(function (item) return ArrayFilterPipe._hasOptions(item, options); );
;
return ArrayFilterPipe;
());
ArrayFilterPipe.TYPES =
OBJECT: 'object',
STRING: 'string',
UNDEFINED: 'undefined'
;
/*
TESTING
--------------------------------------------------
*/
var pipe = new ArrayFilterPipe();
var array = [null, undefined, , true, 123123, 'Jeke HeNry', 'joe', 'joe hen', , [], fake: 'hen' , name: 'hen' , name: 'johenrik', country: 'hen' , name: 'joe dick', city: 'hen' , name: 'Jeke HeNry', country: 'zxy' ];
var options = null;
/* REF: http://***.com/questions/11403107/capturing-javascript-console-log */
var oldLog = console.log;
console.log = function (message)
var _arguments = arguments;
var div = Object.keys(arguments).map(function (key) return Number(key); ).reduce(function (result, key)
result = result || document.createElement('div');
var isJSON = (_arguments[key] != null && (typeof (_arguments[key]) === 'object' || Array.isArray(_arguments[key])));
var span = document.createElement(isJSON ? 'pre' : 'span');
span.innerHTML = isJSON ? JSON.stringify(_arguments[key], undefined) : _arguments[key].replace('\n', '</br></br>');
result.appendChild(span);
return result;
, null);
document.body.appendChild(div);
oldLog.apply(console, arguments);
;
function test()
console.log('options', options);
console.log('result', pipe.transform(array, options));
console.log('case : 01');
console.log('---------------------------------------------------');
options = 'hen';
test();
console.log('\ncase : 02');
console.log('---------------------------------------------------');
options = name: 'hen' ;
test();
options = [['name', 'hen']];
test();
console.log('\ncase : 03');
console.log('---------------------------------------------------');
options = name: 'hen', country: 'hen' ;
test();
options = [['name', 'hen'], ['country', 'hen']];
test();
console.log('\ncase : 04');
console.log('---------------------------------------------------');
options = name: 'hen', city: 'hen', fake: true ;
test();
options = [['name', 'hen'], ['country', 'hen'], ['fake', true]];
test();
【讨论】:
【参考方案6】:我假设你有一个包含这样列的数组:
[col1:"col1",col2:"col2",col3:"col3"]
我还省略了所有类型检查、空指针和错误处理。当前的解决方案是我尝试使用数组的示例:
myData:Array<any> = [col1:"a",col2:"b",col3:"cadd",
col1:"abba",col2:"bobba",col3:"cadd",
col1:"abba",col2:"bobba",col3:"cool",
col1:"a",col2:"bobba",col3:"cool"];
和管道:
@Pipe(
name: 'dataFilter'
)
export class DataFilterPipe implements PipeTransform
transform(value: any, args?: any): any
return value.filter(item =>
var matchesAll = true;
for(var i = 0; i<args.length; i++)
// check if your data contains the column and the value defined in args.
if(item.hasOwnProperty(args[i][0]) && item[args[i][0]]==args[i][1])
continue;
else // at least one column did not match,
matchesAll = false;
return matchesAll;
);
然后你可以调用
dataFilter.transform(myData,[["col1","abba"],["col2","bobba"],["col3","cool"]]);
为了得到一个结果,即转换后的第 3 行:[col1:"abba",col2:"bobba",col3:"cool"]
。
注意:在我的示例中,您可能需要调整列的名称以使其适用于您的代码。
编辑:使用此解决方案,您还可以传递任意数量的列。
例如dataFilter.transform(myData,[["col3","cool"]]);
这将导致转换后的最后两行(来自我的示例):
[col1:"abba",col2:"bobba",col3:"cool",col1:"a",col2:"bobba",col3:"cool"]
编辑:在评论指出代码不起作用后,我提供了上面示例的 plunkr:https://plnkr.co/edit/VdpGJWyzWUVFzYNDSz1g
【讨论】:
@JeetenParmar 我添加了一个工作 plunkr:plnkr.co/edit/VdpGJWyzWUVFzYNDSz1g 请看一下【参考方案7】:如下替换你的代码,
export class DataFilterPipe implements PipeTransform
transform(value: Item[], field: string, args: string): Item[]
let filter: string = args ? args.toLocaleLowerCase() : null;
return filter ? value.filter((item : Item) =>
Item[field].toLocaleLowerCase().indexOf(filter) != -1) : value;
在 Html 页面中,
<tbody *ngFor="let item of items | dataFilter : columnName : value ">
【讨论】:
这只是一个过滤器参数。我需要多个参数。 你到底想做什么?在多列上使用单个过滤器参数进行过滤,还是在单列上使用多个过滤器参数进行过滤?请清除它。 多列上的多个过滤器。我在数组中传递数据,例如[['column1',value1],['column2',value2],['column3',value3]]
。以上是关于使用一个管道角度 2 过滤多个列的主要内容,如果未能解决你的问题,请参考以下文章