Angular 4 Pipe Filter

后端 未结 4 1080
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-28 08:30

I am trying to use a custom pipe to filter my *ngFor loop using an input field with ngModel. With my other custom pipe (sortBy), it works perfectly fine. Howeve

相关标签:
4条回答
  • 2020-11-28 09:05

    I know this is old, but i think i have good solution. Comparing to other answers and also comparing to accepted, mine accepts multiple values. Basically filter object with key:value search parameters (also object within object). Also it works with numbers etc, cause when comparing, it converts them to string.

    import { Pipe, PipeTransform } from '@angular/core';
    
    @Pipe({name: 'filter'})
    export class Filter implements PipeTransform {
        transform(array: Array<Object>, filter: Object): any {
            let notAllKeysUndefined = false;
            let newArray = [];
    
            if(array.length > 0) {
                for (let k in filter){
                    if (filter.hasOwnProperty(k)) {
                        if(filter[k] != undefined && filter[k] != '') {
                            for (let i = 0; i < array.length; i++) {
                                let filterRule = filter[k];
    
                                if(typeof filterRule === 'object') {
                                    for(let fkey in filterRule) {
                                        if (filter[k].hasOwnProperty(fkey)) {
                                            if(filter[k][fkey] != undefined && filter[k][fkey] != '') {
                                                if(this.shouldPushInArray(array[i][k][fkey], filter[k][fkey])) {
                                                    newArray.push(array[i]);
                                                }
                                                notAllKeysUndefined = true;
                                            }
                                        }
                                    }
                                } else {
                                    if(this.shouldPushInArray(array[i][k], filter[k])) {
                                        newArray.push(array[i]);
                                    }
                                    notAllKeysUndefined = true;
                                }
                            }
                        }
                    }
                }
                if(notAllKeysUndefined) {
                    return newArray;
                }
            }
    
            return array;
        }
    
        private shouldPushInArray(item, filter) {
            if(typeof filter !== 'string') {
                item = item.toString();
                filter = filter.toString();
            }
    
            // Filter main logic
            item = item.toLowerCase();
            filter = filter.toLowerCase();
            if(item.indexOf(filter) !== -1) {
                return true;
            }
            return false;
        }
    }
    
    0 讨论(0)
  • 2020-11-28 09:13

    Pipes in Angular 2+ are a great way to transform and format data right from your templates.

    Pipes allow us to change data inside of a template; i.e. filtering, ordering, formatting dates, numbers, currencies, etc. A quick example is you can transfer a string to lowercase by applying a simple filter in the template code.

    List of Built-in Pipes from API List Examples

    {{ user.name | uppercase }}
    

    Example of Angular version 4.4.7. ng version


    Custom Pipes which accepts multiple arguments.

    HTML « *ngFor="let student of students | jsonFilterBy:[searchText, 'name'] "
    TS   « transform(json: any[], args: any[]) : any[] { ... }
    

    Filtering the content using a Pipe « json-filter-by.pipe.ts

    import { Pipe, PipeTransform, Injectable } from '@angular/core';
    
    @Pipe({ name: 'jsonFilterBy' })
    @Injectable()
    export class JsonFilterByPipe implements PipeTransform {
    
      transform(json: any[], args: any[]) : any[] {
        var searchText = args[0];
        var jsonKey = args[1];
    
        // json = undefined, args = (2) [undefined, "name"]
        if(searchText == null || searchText == 'undefined') return json;
        if(jsonKey    == null || jsonKey    == 'undefined') return json;
    
        // Copy all objects of original array into new Array.
        var returnObjects = json;
        json.forEach( function ( filterObjectEntery ) {
    
          if( filterObjectEntery.hasOwnProperty( jsonKey ) ) {
            console.log('Search key is available in JSON object.');
    
            if ( typeof filterObjectEntery[jsonKey] != "undefined" && 
            filterObjectEntery[jsonKey].toLowerCase().indexOf(searchText.toLowerCase()) > -1 ) {
                // object value contains the user provided text.
            } else {
                // object didn't match a filter value so remove it from array via filter
                returnObjects = returnObjects.filter(obj => obj !== filterObjectEntery);
            }
          } else {
            console.log('Search key is not available in JSON object.');
          }
    
        })
        return returnObjects;
      }
    }
    

    Add to @NgModule « Add JsonFilterByPipe to your declarations list in your module; if you forget to do this you'll get an error no provider for jsonFilterBy. If you add to module then it is available to all the component's of that module.

    @NgModule({
      imports: [
        CommonModule,
        RouterModule,
        FormsModule, ReactiveFormsModule,
      ],
      providers: [ StudentDetailsService ],
      declarations: [
        UsersComponent, UserComponent,
    
        JsonFilterByPipe,
      ],
      exports : [UsersComponent, UserComponent]
    })
    export class UsersModule {
        // ...
    }
    

    File Name: users.component.ts and StudentDetailsService is created from this link.

    import { MyStudents } from './../../services/student/my-students';
    import { Component, OnInit, OnDestroy } from '@angular/core';
    import { StudentDetailsService } from '../../services/student/student-details.service';
    
    @Component({
      selector: 'app-users',
      templateUrl: './users.component.html',
      styleUrls: [ './users.component.css' ],
    
      providers:[StudentDetailsService]
    })
    export class UsersComponent implements OnInit, OnDestroy  {
    
      students: MyStudents[];
      selectedStudent: MyStudents;
    
      constructor(private studentService: StudentDetailsService) { }
    
      ngOnInit(): void {
        this.loadAllUsers();
      }
      ngOnDestroy(): void {
        // ONDestroy to prevent memory leaks
      }
    
      loadAllUsers(): void {
        this.studentService.getStudentsList().then(students => this.students = students);
      }
    
      onSelect(student: MyStudents): void {
        this.selectedStudent = student;
      }
    
    }
    

    File Name: users.component.html

    <div>
        <br />
        <div class="form-group">
            <div class="col-md-6" >
                Filter by Name: 
                <input type="text" [(ngModel)]="searchText" 
                       class="form-control" placeholder="Search By Category" />
            </div>
        </div>
    
        <h2>Present are Students</h2>
        <ul class="students">
        <li *ngFor="let student of students | jsonFilterBy:[searchText, 'name'] " >
            <a *ngIf="student" routerLink="/users/update/{{student.id}}">
                <span class="badge">{{student.id}}</span> {{student.name | uppercase}}
            </a>
        </li>
        </ul>
    </div>
    
    0 讨论(0)
  • 2020-11-28 09:23

    Here is a working plunkr with a filter and sortBy pipe. https://plnkr.co/edit/vRvnNUULmBpkbLUYk4uw?p=preview

    As developer033 mentioned in a comment, you are passing in a single value to the filter pipe, when the filter pipe is expecting an array of values. I would tell the pipe to expect a single value instead of an array

    export class FilterPipe implements PipeTransform {
        transform(items: any[], term: string): any {
            // I am unsure what id is here. did you mean title?
            return items.filter(item => item.id.indexOf(term) !== -1);
        }
    }
    

    I would agree with DeborahK that impure pipes should be avoided for performance reasons. The plunkr includes console logs where you can see how much the impure pipe is called.

    0 讨论(0)
  • 2020-11-28 09:25

    The transform method signature changed somewhere in an RC of Angular 2. Try something more like this:

    export class FilterPipe implements PipeTransform {
        transform(items: any[], filterBy: string): any {
            return items.filter(item => item.id.indexOf(filterBy) !== -1);
        }
    }
    

    And if you want to handle nulls and make the filter case insensitive, you may want to do something more like the one I have here:

    export class ProductFilterPipe implements PipeTransform {
    
        transform(value: IProduct[], filterBy: string): IProduct[] {
            filterBy = filterBy ? filterBy.toLocaleLowerCase() : null;
            return filterBy ? value.filter((product: IProduct) =>
                product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1) : value;
        }
    }
    

    And NOTE: Sorting and filtering in pipes is a big issue with performance and they are NOT recommended. See the docs here for more info: https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe

    0 讨论(0)
提交回复
热议问题