Issue
I am refactoring some angular code that subscribed to data from a service call. Instead I want the data to be returned from the service as an observable so I can utilize the async pipe so I do not have to unsubscribe from everything at the end. My old code looked something like this:
Component.ts
people: Person[] = [];
getPeople(){
this.apiService.GetPeople().subscribe((result) => {
this.people = result;
}));
}
Then elsewhere I can access the data using this.people
to look through the data and do whatever I need to.
Now I want to do something like the following. But if I do, how do I access the same data within the component without subscribing to the data and having to unsubscribe on ngOnDestroy
Component.ts
people$ = Observable<Person[]>;
getPeople(){
this.people$ = this.apiService.people$;
}
And in my service:
ApiService.ts
private allPeople: BehaviorSubject<Person[]> = new BehaviorSubject<Person[]>([]);
people$ = this.allPeople.asObservable();
With the people$ now being an observable I can do the following in my html:
Index.html
<div *ngIf="people$ | async">
</div>
From what I understand, doing that will automatically unsubscribe as needed. But now that I have the data in the component as people$ which is an observable, how can I access the data? For example, I have an observable of cities and I want to filter them based on whether the observable people are marked with display = true
. I cannot do something like below. So what is the best way to get the same functionality?
Component.ts
let peopleToUse = this.people$.filter(m => m.display === true).map((filter) => {return filter.city});
this.cities$ = this.cities$.filter(m => peopleToUse.includes(m.city));
The end result would be a list of cities that are only in the list of people's city propery where the display = true. Is there a way to do this without subscribing? Because if I subscribe, doesn't it defeat the purpose of the async pipe in the first place?
UPDATE If I have the two observables cities$ and people$, how do I update the cities$ based on changes to people$ ?. For example if the user updates one of the people to have the display = false instead of true, I would want to filter out that record from the cities$.
Example
updatePerson(person: Person){
this.apiService.updatePerson(person);
//update this.cities$ to filter again.
let peopleToUse = this.people$.filter(m => m.display === true).map((filter) => {return filter.city});
this.cities$ = this.cities$.filter(m => peopleToUse.includes(m.city));
}
Solution
You can .pipe() this.people$ and use .tap() operator.
Like this:
people$ = Observable<Person[]>;
getPeople() {
this.people$ = this.apiService.people$.pipe(
tap((people) => {
<your logic here>
})
);
}
Now this logic is triggered when the async pipe is called on people$ in the template.
Update: Use .combineLatest()
//component.ts
ngOnInit(): void {
// Assuming you have services that provide these observables
this.people$ = this.peopleService.getPeople();
this.cities$ = combineLatest([this.people$, this.cityService.getCities()])
.pipe(
map(([people, cities]) => {
const updatedCities = cities.filter(m => people.includes(m.city));
return updatedCities;
})
);
}
component.html
<div *ngIf="(people$ | async) as people">
<!-- Display people list -->
<div *ngFor="let person of people">
{{ person.name }}
</div>
</div>
<div *ngIf="(cities$ | async) as cities">
<!-- Display cities list -->
<div *ngFor="let city of cities">
{{ city.name }}
</div>
</div>
Answered By - oksd
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.