Reputation: 1323
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
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
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