In Angular, how to display original data and filtered data on the same page?

Issue

Let’s say I have some data from a service call, and I store it as originalData.

Now in addition, I must filter the data and also display that filtered data. The way I’m doing that is like this:

this.service.getData((data) => {
  this.originalData = data;
  this.filteredData = data.filter(/* some filter condition */);
});

I have originalData and filteredData bound on the html template. This solution works. As I require more and more of the filtered versions to be displayed, so I’m storing more and more of these filtered or otherwise modified objects on my class.

This seems like a bad practice, as the state of my class is increasing and getting out of control, and managing the different copies of the data is getting cumbersome.

What would a better practice be?

Solution

Transforming data

You want to just transform the existing data. Here are two very simple examples on how to do that, both synchronously and asynchronously. Since usually the data from a service is async.

Synchronous

For synchronous data you can just use a function that takes your data as a parameter and returns the desired form of your transformed data.

component.ts:

data = [10, 20, 30, 40, 50, 60]

divisibleBy20(numbers: number[]) {
  return numbers.filter(number => number % 20 === 0)
}

component.html:

{{ data }}
{{ divisibleBy20(data) }}

Asynchronous

For asynchronous data RxJS provides tons op operators to pipe the data. You can find more operators here.

Service.ts:

getData() {
  return of([1, 2, 3, 4, 5, 6]);
}

Component.ts:

all$: Observable<number[]>
evens$: Observable<number[]>

constructor(
  private dataService: DataService
){}

ngOnInit() {
  this.all$ = this.dataService.getData()
  this.evens$ = this.all$.pipe(
    map((numbers: number[]) => numbers.filter(number => number % 2 === 0))
  )
}

Component.html:

{{ all$ | async }}
{{ evens$ | async }}

Here is an example for you to play with on Stackblitz.

Here is an example of what NOT to do according to the Angular documentation.
These kind of pipes have their uses, but can be triggered a lot for no reason. To prevent this u can make custom pipes ‘pure’. This way Angular executes the pipe only when it detects a pure change to the input value.

You can do this by adding pure: true to the decorator:

@Pipe({
  name: 'myPipe',
  pure: true
})
export class MyPipe implements PipeTransform {
    // ...
}

Answered By – H3AR7B3A7

Answer Checked By – Pedro (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.