Angular - 5 different ways to filter ngFor (Code examples included)

Daniel Kreider
Daniel Kreider - 04. Oct. 2022
  • Angular Tricks
  • Angular Pipes
  • Angular ngFor

One of Angular's coolest features is the ngFor directive.

I remember how fascinated I was the first time I used it.

Why?

Because it made jQuery look so... um mm... dumb. 😉

duh

But what if I want to filter the results displayed by ngFor?

How do you apply a filter to only show specific results in an ngFor loop?

Or how do you exclude a specific item when using Angular's ngFor?

Is there some sort of where condition that we can use?

Today I'm going to show you exactly how to create and use an ngFor filter. This will allow you to filter the results that are displayed and exclude or include what you want to be displayed to your users.

filter

There are at least 5 different ways to filter the ngFor in Angular.

And the best part?

I've included a bonus idea at the bottom of this article that I know will serve some of my readers.

Ready to start? Let's dive in.

1. Create a custom filter pipe

Imagine we have a list of people to display.

But in this case we only want to display the users that are under the age of 18.

Here's our component's Typescript file.

import { Component } from '@angular/core';

@Component({
  selector: 'app-filter-demo',
  templateUrl: './filter-demo.component.html',
  styleUrls: ['./filter-demo.component.css']
})
export class FilterDemoComponent {
  people = [
    {name: 'Bob', age: 6}, 
    {name: 'Alice', age: 21}, 
    {name: 'Becky', age: 13}, 
    {name: 'Joe', age: 45},
    {name: 'Sally', age: 28}
  ];

  constructor() { }
}

The next step is to create a custom filter pipe.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'filterPeople'
})
export class FilterPeoplePipe implements PipeTransform {

  transform(values: any[], ...args: unknown[]): any[] {
    return values.filter(v => v.age < 18);
  }

}

And finally use it in the template file like this.

<ul>
    <li *ngFor="let person of people | filterPeople">{{ person.name }}</li>
</ul>

That's one way to filter the ngFor directive.

But what if there was a more generic approach?

Like a pipe that we could use to filter every type of lists and objects?

2. Create a callback pipe

The first step is to create a new pipe called the callback pipe.

Here's how to do it with the Angular CLI.

ng generate pipe callback

And here's the code for the new pipe.

import { PipeTransform, Pipe } from '@angular/core';

@Pipe({
    name: 'callback',
    pure: false
})
export class CallbackPipe implements PipeTransform {
    transform(items: any[], callback: (item: any) => boolean): any {
        if (!items || !callback) {
            return items;
        }
        return items.filter(item => callback(item));
    }
}

So how does this work?

Well, we pass in a custom callback function that is used to filter results.

It works like this.

import { Component } from '@angular/core';

@Component({
  selector: 'app-filter-demo',
  templateUrl: './filter-demo.component.html',
  styleUrls: ['./filter-demo.component.css']
})
export class FilterDemoComponent {
  people = [
    {name: 'Bob', age: 6}, 
    {name: 'Alice', age: 21}, 
    {name: 'Becky', age: 13}, 
    {name: 'Joe', age: 45},
    {name: 'Sally', age: 28}
  ];

  constructor() { }

  findNonAdults(person: any): any {
    return person.age < 18;
  }
}

And in our HTML template we call it like this.

<ul>
    <li *ngFor="let person of people | callback:findNonAdults">{{ person.name }}</li>
</ul>

3. Use a filter function in your component

In this scenario, instead of using a pipe we'll use a function to filter the results.

For an example we'll assume we have the same component that wants to display a list of users under the age 18.

import { Component } from '@angular/core';

@Component({
  selector: 'app-filter-demo',
  templateUrl: './filter-demo.component.html',
  styleUrls: ['./filter-demo.component.css']
})
export class FilterDemoComponent {

  people = [
    {name: 'Bob', age: 6}, 
    {name: 'Alice', age: 21}, 
    {name: 'Becky', age: 13}, 
    {name: 'Joe', age: 45},
    {name: 'Sally', age: 28}
  ];

  constructor() { }

  findNonAdults(people: any[]): any[] {
    return people.filter(p => p.age < 18);
  }
}

Now, inside of our component's template file we'll run the people object through our filter function.

Like this.

<ul>
    <li *ngFor="let person of findNonAdults(people)">{{ person.name }}</li>
</ul>

4. Use the SlicePipe

Slicing? Or filtering?

Angular's slice pipe is not exactly a filter pipe so it might not be powerful enough for your needs.

It's used to select a subset of elements from an array. Which means that if you want to filter out a determined amount of elements then this is probably the way to go.

According to the Angular docs if we do something like this.

@Component({
  selector: 'slice-list-pipe',
  template: `<ul>
    <li *ngFor="let i of collection | slice:1:3">{{i}}</li>
  </ul>`
})
export class SlicePipeListComponent {
  collection: string[] = ['a', 'b', 'c', 'd'];
}

We'll get an output like this.

<li>b</li>
<li>c</li>

5. Use ngIf with a filter function

Take the example we've used previously, let's say we have a component with a list of users.

We'll also create a function named isAdult(person: any) that is used to check if a specified person is an adult or not.

import { Component } from '@angular/core';

@Component({
  selector: 'app-filter-demo',
  templateUrl: './filter-demo.component.html',
  styleUrls: ['./filter-demo.component.css']
})
export class FilterDemoComponent {

  people = [
    {name: 'Bob', age: 6}, 
    {name: 'Alice', age: 21}, 
    {name: 'Becky', age: 13}, 
    {name: 'Joe', age: 45},
    {name: 'Sally', age: 28}
  ];

  constructor() { }

  isAdult(person: any): boolean {
    return person.age > 17;
  }
}

We can then use the isAdult(...) function with ngIf to hide results we don't want to show.

Like this.

<div *ngFor="let person of people">
    <ng-container *ngIf="!isAdult(person)">
        <p >{{ person.name }}</p>
    </ng-container>
</div>

6. Bonus Idea: Use ng2-search-filter

The ng2-search-filter package is limited and might not be powerful enough for you because it's limited to filtering strings.

But again, it might be exactly what you need so here's how to use it if you're curious.

The first step is to install the package.

npm i ng2-search-filter --save

The next step is to import the search filters into your module.

import { Ng2SearchPipeModule } from 'ng2-search-filter';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
    Ng2SearchPipeModule
  ],
  providers: [],
  bootstrap: [...]
})
export class AppModule { }

And finally, here's how to use it.

<div *ngFor="let person of people | filter:'filterString'">
    <p >{{ person.name }}</p>
</div>

What approach will you use?

Today I've showed you 6 different ways that you can use - things like Angular pipes or functions - to sort an ngFor loop in Angular.

Now I'd like to hear from you:

Which approach works best for you?

And why?

Let me know by leaving a comment below right now.

signature

Angular Consultant