Jake Bruun
Jake Bruun

Reputation: 1323

Filter an array of objects using an Observable filter

I'm struggling to figure the correct way to filter an array of objects using RxJS 6.

Here's the scenario. I have users: User[], filter: FormControl, and another array of filteredUsers: User[]. What I would like to do is filter the list the users based on the value contained in the filter. The only way I was able to figure this out was to use tap, and while this works, it just doesn't seem like the right way to do it...plus the whole list is "filtered out" until the filter control has its first valueChange.

this.filter.valueChanges.pipe(
  tap((term) => {
    this.filteredUsers = this.users.filter(u => u.name.indexOf(term) != -1)
  })).subscribe()

Any help would be greatly appreciated.

Upvotes: 1

Views: 842

Answers (2)

bryan60
bryan60

Reputation: 29325

you're right that tap isn't the "right" way to do it... the right way is to do it in subscribe...

this.filter.valueChanges.pipe(startWith('')).subscribe(
  (term) => {
    this.filteredUsers = (term) ? this.users.filter(u => u.name.indexOf(term) != -1) : this.users;
});

and add in a blank check that doesn't filter, and a start with that kicks off the stream. done and done. Don't add complexity where you don't need it. rxjs recommends side effects occur in your subscribe function, everything else SHOULD be transformative / functional, and setting a value on the controller is a side effect.

If you want to get really reactive, you can throw in an async pipe for good measure

this.filteredUsers$ = this.filter.valueChanges.pipe(startWith('')).tap(
  (term) => {
    return (term) ? this.users.filter(u => u.name.indexOf(term) != -1) : this.users;
});

then in HTML instead of

*ngFor="let user of filteredUsers"

do:

*ngFor="let user of filteredUsers$ | async"

the benefit here is automatic subscription cleanup and better support for onpush change detection.

Upvotes: 2

Kaizen Programmer
Kaizen Programmer

Reputation: 3818

Just move the tap function into the subscribe:

this.filter.valueChanges.subscribe((term) => {
    this.filteredUsers = this.users.filter(u => u.name.indexOf(term) != -1)
  });

Upvotes: 0

Related Questions