Search code examples
angulartypescriptrxjsangular-pipe

Angular 9 filter results of async pipe


I am kind of new at angular and I am doing an application to learn better. I have a problem about binding and filtering results of a http call. At below code I try to bind a list of some data.

At service I have a call like this

 getTestFields(): Observable<Engagement[]> {
   return this.httpClient.get<Engagement[]>(this.url + '/testFields');
 }

It basically returns a list of some test fields; and at component.ts I am binding the results of call to an observable variable.

dataSet$: Observable<Engagement[]>;
ngOnInit(): void {
  this.dataSet$ = this.service.getTestFields();
}

And at the html template I bind the data like below:

<table class="table table-hover" *ngIf="dataSet$ | async as resultSet; else loading">
        <tr *ngFor="let item of resultSet" >
            <td>{{item.testName}}</td>
            <td>{{item.planned}}</td>
            <td>{{item.workingOn}}</td>
            <td>{{item.reviewed}}</td>
        </tr>   </table>

Until here I have no problem; I get the data successfully and show in table. The problem is filtering; I couldn't figure out how I can filter the data that I already got from server. I don't want to make server calls for filtering data, I want to filter the current list that I already got.

I tried something like below but it didn't work.

filter() {
    this.dataSet$ = this.dataSet$.pipe(
    switchMap(data => {
      return data.filter(p => p.planned)
    })
  );
 }

How can I filter existing observable list without sending a new call to server ?


Solution

  • Try the rxjs map operator coupled with array filter.

    Map transforms the observable, so in this case we are using it to transform the array to only include the items where planned is true.

    import { map } from 'rxjs/operators';
    .....
    ngOnInit(): void {
      this.dataSet$ = this.service.getTestFields().pipe(
        map(data => data.filter(p => p.planned)),
      );
    }
    

    You can also filter emissions from the Observable using the filter operator of rxjs but I don't think you need it in this case.

    ================ Use of RxJS Filter ===================

    import { filter } from 'rxjs/operators';
    ...
    ngOnInit(): void {
      this.dataSet$ = this.service.getTestFields().pipe(
        // make sure data is truthy and has a length before emitting to 
        // the consumer (in this case it is the HTML).
        filter(data => !!data && !!data.length),
      );
    }