使用一个管角2过滤多个列

时间:2017-01-16 08:57:14

标签: javascript angular typescript filter pipe

我正在尝试仅使用一个Array基于多个列过滤Pipe个数据。现在,它过滤第一列值。请检查下面的代码并帮我解决这个问题。

我的代码:

@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]]等数据。

7 个答案:

答案 0 :(得分:23)

这是使用作为多列过滤器传递的对象的解决方案。我发现它传递2D数组更方便:

    @Pipe({
        name: 'filter'
    })
    export class FilterPipe implements PipeTransform {
        transform(items: Array<any>, filter: {[key: string]: any }): Array<any> {
            return items.filter(item => {
                let 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.

答案 1 :(得分:2)

替换您的代码,如下所示,

 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 ">

答案 2 :(得分:1)

我假设您有一个包含这样的列的数组:

[{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"}]

编辑:在评论说明代码无法正常工作后,我提供了上述示例的一个内容:https://plnkr.co/edit/VdpGJWyzWUVFzYNDSz1g

答案 3 :(得分:1)

这是我对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;

答案 4 :(得分:0)

您可以看到整个工作 ArrayFilterPipe.ts @ http://typescript.io/uN29xRdF1Agtypescriptlang.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

获取灵感来构建类似于角度1.x的数组/对象过滤器

&#13;
&#13;
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://stackoverflow.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();
&#13;
&#13;
&#13;

答案 5 :(得分:0)

HTML标记:

transform(items: any, filter: any, isAnd: bool): any {
  if (filter && Array.isArray(items)) {
   let filterKeys = Object.keys(filter);
    if (isAnd) {
     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;
  }
}

转换功能:

timeZone

参考:https://long2know.com/2017/04/angular-pipes-filtering-on-multiple-keys/

答案 6 :(得分:0)

我必须拥有一个Pipe,它可以通过特定的属性值和称为“ All”的通用值进行过滤。用户可以通过从下拉列表中选择它们来动态调整这些过滤器(从而使用效率较低的foreach()配置)。

在组件中(默认为“全部”)

pure: false

在模板中

public filters = { status: "All", condition: "All", other: "All" };
<div *ngFor="let item of items | filter:filters">