使用一个管道角度 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>

因此,有两个人符合我们的条件:JohnMike

这里是工作插件: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 过滤多个列的主要内容,如果未能解决你的问题,请参考以下文章

角度 6 过滤异步管道结果

特定列上的角度表过滤器

shell 管道命令与过滤器

以角度将列标题过滤器保存在 ag-grid 中

剑道列过滤器内的角度材料日期选择器问题

如何正确过滤角度数组