Issue
I’ve created an app to search employes that use observables.
It’s very simple:
template for subscribe
<div class="row row-cols-1 row-cols-md-6 g-2">
<ng-container *ngIf="emps.length">
<div class="col" *ngFor="let emp of emps">
<div class="card h-100">
<img *ngIf="emp.image" [src]="emp.image" class="card-img-top" alt="image">
<div class="card-body">
<span *ngIf="emp.actived" class="badge rounded-pill bg-success"
style="position: absolute;top: 2px;right: 2px;">✓
</span>
<h5 class="card-title">{{emp.name| uppercase}}</h5>
<!-- <pre class="card-text">{{emp.phones}}</pre> -->
</div>
</div>
</div>
</ng-container>
</div>
Component:
emps: IToList[] = [];
change(){//e: HTMLInputElement) {
this.service.getPeople(this.searchTerm).pipe(
map(data => data.map(d => {
let c = new Person(d._id, d.actived, d.name, d.phones, d.image);
return c.getPerson();
}))
).subscribe(data=>this.emps=data);
}
It works fine for me:
The async pipe version.
template:
<div class="row row-cols-1 row-cols-md-6 g-2">
<ng-container *ngIf="people$|async as emps">
<div class="col" *ngFor="let emp of emps">
<div class="card h-100">
<img *ngIf="emp.image" [src]="emp.image" class="card-img-top" alt="image">
<div class="card-body">
<span *ngIf="emp.actived" class="badge rounded-pill bg-success"
style="position: absolute;top: 2px;right: 2px;">✓
</span>
<h5 class="card-title">{{emp.name | uppercase}}</h5>
<!-- <pre class="card-text">{{emp.phones}}</pre> -->
</div>
</div>
</div>
</ng-container>
</div>
Component:
people$!: Observable<IToList[]>;
change(){//e: HTMLInputElement) {
this.people$ = this.service.getPeople(this.searchTerm).pipe(
map(data => data.map(d => {
let c = new Person(d._id, d.attivo, d.nominativo, d.telefoni, d.immagine);
return c.getPerson();
}))
);
}
Why is the app more responsive when I’m manually subscribing instead of using an async pipe?
Updated 10/06/2022
The image src is a base64 string and its size is 3mb.
Solution
When you use async Pipe you will use ChangeDetectionStrategy
in OnPush
it will improve your performance.
Async pipe it`s better in most of the cases because it is in charge to handle the subscription and unsuscription and notify which reactive part of the code is going to be rendered. Also you prevent possible memory leaks.
Even you can remove the ngif and the container where is the main subscription just by adding the async pipe in the *ngFor="let emp of (people$ | async)"
***************************** Edit ********************************************
The main problem in you code that is mentioned by @Get Off My Lawn.
Each time the search term change your observable is been recreated and it is the difference between with your 2 examples.
What You can do is in the ngOninit add the people$ observable with the form control of the search input then adding a switchMap operator to execute the service call then you will have the same observable and subscription always
ngOnini{
this.people$ = this.form.get('searchInput').valueChanges.pipe(
switchMap(searchTerm => this.service.getPeople(this.searchTerm)),
map(data => => data.map(d => {
let c = new Person(d._id, d.actived, d.name, d.phones, d.image);
return c.getPerson();
}))
);
}
Answered By – Abel Valdez
Answer Checked By – Timothy Miller (AngularFixing Admin)