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


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 Angular 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. Use ngx-search-filter

The ngx-search-filter package is a mighty little Angular library.

It's nothing more then a lightweight Angular search filter pipe.

demo-image

The first step is to install the package.

npm i ngx-search-filter --save

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

import { NgxSearchFilterModule } from 'ngx-search-filter';

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

And finally, here's how to use it.

<input type="text" [(ngModel)]="term">
        <div *ngFor = "let item of items | filter:term" >
          <p>{{item.name}}</p>
</div>

2. Create a custom filter pipe

Imagine we need to display a list of people.

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

Our Angular component's Typescript file might look something 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() { }
}

The next step is to create a custom Angular pipe to act as our ngFor filter.

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?

3. 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>

This approach is more flexible and allows you to create an ngFor filter pipe that can be used all over your Angular application... wherever you dandy well please.

🥳 🥳 🥳

4. 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>

5. 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>

6. Bonus Idea - 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>

What kind of ngFor filter 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?

Drop me a message and let me know.

signature

Angular Consultant