Easily making double-POST using Angular (WTF is Cold Observable)

Georgi Parlakov
ng-gotchas
Published in
3 min readJul 19, 2018

ng-gotchas #5 — subscribing twice makes two POST-s

I will be using the older (now obsolete) angular HTTP module for various reasons: (1) it was what we used when I initially created a bug in our application which was causing the double POST (#ng-gotcha) and also (2) to experiment making stackblitz run a not-latest version of angular — like 2.4.10. In general any ‘cold’ observable would display the same behavior in similar circumstances.

With that out of the way let’s jump to the app we are building: Say that app supports registers users. And let’s say that the app has a simple UI. Consider this:

Fill in email and password and hit Enter. Try it a couple of times and note the POSTs counter incrementing.

There is the RegisterService and the AppComponent and the UI that allows you to enter email and password and register a user. The service returns an Observable<User> that is directly passed to the template via the registerdUser$ property. In the template app.component.html we use the async pipe for handling subscription and unsubscribtion.

Now let’s say we need to make the app’s UI a bit more sophisticated. We only want to show the user having registered after they actually do register successfully. So we add *ngIf=”(registerdUser$ | async) != null” to our element to only show it when there is something to actually show. Makes sense right?

Notice how now for every user you add there are 2 POST requests getting sent. Odd? Not really — the second async pipe also subscribes to our regiesredUser$ observable and causes the second request*. Something similar happened to us in our app. How to handle that?

*Let’s expand on this a bit. Consider the observable that http.post() returns just a function that waits to get called. When it gets called it will new up an XHR and send a request to the server. That function is there for you and you can call it any number of times that you like. This “calling” is the subscription. And this function is the cold observable. If it was hot observable the act of creation of the function(observable instantiation) would actually make the call to the server.

The cold observable variant
The hot observable variant

Generally when you get a cold observable you could transform it to a hot “manually” or with an operator.

Manually would involve (1) creating a local subject (in this case BehaviorSubject), (2) creating a single subscription to the cold observable and (3) pouring the values it emits in the subject. Finally expose the subject to your template. Something of the sort:

There’s an argument to be made here that the service — RegisterService should handle that — i.e. make these changes to the service itself and expose a BehaviorSubject as Observable. Use that as the result of the .regiser(email, password) result. The argument would be that the service should hide from us the complexities of the observable it returns. Works the same. Up to the authoring code person and any other team members working on the same code base. This might look something like this:

And there’s an operator that we can use called multicast which creates a subscription to the ‘cold’ observable making it ‘hot’ and sharing the result with any and all subscribers. It might look like this:

In the demos I’ve used the cools services that Stackblitz and https://reqres.in provide.

--

--

Georgi Parlakov
ng-gotchas

Angular and DotNet dev. RxJs explorer. Testing proponent. A dad. Educative.io course author. https://gparlakov.github.io/