'How to update a subscription to a GET-request after posting new data to the backend
I have implemented a service which utilizes Angular's HttpClient to make a GET-request to my backend. It returns a list of employees:
getAllEmployees(): Observable<Employee[]> {
return this.httpClient.get<Employee[]>(this.EMPLOYEES_URL);
}
I subscribe to this service inside the ngOnInit() method of a table-component, filling an array with the returned data. The rows of my table are built dynamically from the content inside the array.
Now, I am posting a new employee to my backend. The table, however, is not updated.
My understanding of Angular observables is that they watch the backend (in this case) and whenever something changes, the code inside the subscription is executed. Apparently this understanding is wrong and I wonder: How can I force an update of the subscription inside my table-component?
Solution 1:[1]
I think the peice of information you may be missing is that the Observables returned from HttpClient methods complete after the first return.
As you are using 2 separate components you will need some means of informing that new data must be fetched, or some way of keeping the observable open - we can do this with a service. I think the following should work for you.
In the service we could define:
private employeesUpdated$ = new Subject<void>();
employees$ = employeesUpdated$.pipe(
startsWith({}),
switchMap(() =>
this.httpClient.get<Employee[]>(this.EMPLOYEES_URL)
)
);
You could then, on your POST add:
this.httpClient.post<something>(... stuff ...).pipe(
tap(() => {
this.employeesUpdated.next();
})
)
This will allow you to subscribe to employees$ in your component, and each time you post a new one, it will perform a new get request, as the observable will stay open. Do dispose of this subscription properly though!
You can find lots more information about rxjs and Observables from the official docs here: https://rxjs.dev/guide/overview This is also a good resource: https://www.learnrxjs.io/
If you wanted to just append to the initially got array, rather than getting everything from the server after each creation, I think something like this would work:
In the service:
private employeeAdded$ = new Subject<Employee>();
private serverEmployees$ = this.httpClient.get<Employee[]>(this.EMPLOYEES_URL);
employees$ = merge(
serverEmployees$,
employeeAdded$.pipe(
map(x => ([x]))
)
).pipe(
scan((acc, cur) => acc.concat(cur), [])
);
Basically merge will take multiple observables, and output a single one. This goes into scan which will accumulate using a provided function, emitting after each accumulation. Docs for these are https://rxjs.dev/api/index/function/merge and https://rxjs.dev/api/index/function/scan.
For your create (bear in mind for this, parrot the object back from the server on post, so it has an id for the entity):
this.httpClient.post<something>(... stuff ...).pipe(
tap((employee: Employee) => {
this.employeesUpdated.next(employee);
})
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
