In an Angular project, I am trying to retrieve data via an HTTP call. Simultaneously, I need to have an observable whose data is derived from the data obtained through the HTTP call. This way, when the first set of data is updated, the second set will be automatically updated as well. In the example, I have created Item as an object retrieved (a type consisting of id and name), while the derived data is the list of names. Moreover, in this context, I wouldn’t even know how to handle the forceUpdate method.
this is what I tried. I am not sure if it is solid code or if it avoids memory leaks. I am also not sure if it is readable enough.
itemList$: BehaviorSubject<Item[]> = new BehaviorSubject<Item[]>([]);
http = inject(HttpClient);
constructor() {}
fetchList$(filter: string): Observable<Item[]> {
return this.http.get<Item[]>('/api/list');
}
getItemList$(filter: string): Observable<Item[]> {
if (this.itemList$.getValue().length === 0) {
this.fetchList$(filter)
.pipe(
shareReplay(1),
take(1),
tap((res) => this.itemList$.next(res))
)
.subscribe();
}
return this.itemList$.asObservable();
}
getItemNames$(): Observable<string[]> {
return this.itemList$.pipe(
map((items) => items.map((item) => item.name)),
map((names) => Array.from(new Set(names)))
);
}
forceUpdate() {
//how to hanlde this one?
}
this is the component
budgetService = inject(BudgetService);
itemList$ = this.budgetService.getItemList$('test');
nameList$ = this.budgetService.getItemNames$();
update() {
this.budgetService.forceUpdate();
}
and this the html with the async pipe
<div class="content">
<div>
@for (item of itemList$ | async; track $index) {
{{ item.id }}
{{ item.name }}
}
</div>
<div>
@for (name of nameList$ | async; track $index) {
{{ name }}
}
</div>
<button (click)="update()">Update</button>
</div>
Fabrizio is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.