Angular data services with RxJS

224 Views Asked by At

I am programming an Angular application, which talks to a REST-like backend.

The UI consists of a master/detail page, where an element is selectable on the left side and the details are shown to the right. Using angular router, router outlet etc.

The selectable items show a summary of the details. When the detailed item is edited, I want to update the selectable item with the updated information.

I have an api service which uses HttpClient to fetch the values from the backend.

api.service.ts

public getAllItems(): Observable<Item[]> {
return this.http.get<Item[]>(this.apiUrl + '/items')
  .map(response => {
    return response.map((item) => new Item(item));
  });
}

I also have a data service which currently just returns the observable from the api service.

items-data.service.ts

get items$(): Observable<Item[]> {
  return this.api.getAllItems();
}

The master (left-side) component just registers the data service observable.

item-master.component.ts

data$: Observable<Item[]>;

constructor(private itemsDataService: ItemsDataService) { }

ngOnInit() {
  this.data$ = this.itemsDataService.items$;
}

The template uses async pipe and iterates the array to show the summary.

item-master.component.html

<div *ngIf="(data$ | async) as data">

Using this method, the selectable item is not updated automatically when an item is updated in the application.

Now, I am considering changing the data service such that I have an internal Subject which can be observed. When an update is performed through a method in the data service, I can call subject.next() to inform about a change. BUT this application is also used concurrently by other people on other machines/browsers.

Ideally I would like to refetch the data from the backend, but a Subject will effectively act as a "cache" only triggering the first call to the api. How do I most effectively make sure that I fetch the most recent data from the backend and also get updates from changes made locally?

1

There are 1 best solutions below

0
Meir On

Assuming I got your question right, I will change the service to something like this (this is a very schematic description):

items$: Observable<Array<Item>>;

currentItemId$ = new Subject<String>();

currentItem$: Observable<Item> = this.currentItemId$.map(<your fetch code>);

loadItem(itemId) {
  this.currentItemId$.next(itemId);
}

Whenever you click on an item in the master view, it will call the loadItem() method which will fetch the specific value and pipe it to the currentItem$.

This gives you a more service oriented (with store) approach, meaning, you tell it to load an item and consume the item at the exposed observable