How to Streamline Angular Reactivity

Angular embraces RxJS observables. Major features like the router, HTTP client, and reactive forms expose interfaces that either consume or return RxJS observables. Angular schematics and builders can handle observables to perform asynchronous operations. The common package delivers the famousAsyncPipe
for extracting values from observables in component templates. There is even a section dedicated to RxJS and observables in the documentation.
Considering everything, Angular has probably the most comprehensive integration with RxJS observables. Yet, it gets a little complicated once you observe the emitted values in your component class. Let’s create a component that refers to route data and params together to navigate through a list of posts one-by-one. It will look something like this:

To access the route data and params, we will inject the ActivatedRoute
instance. Both data and params are observables, so we will need to subscribe to them if we want to use the emitted values in our component class.
I know I could have piped the route data and params into separate prev$
and next$
streams and employ the async
pipe in the template, but I am trying to make a point here, so please bear with me.
As you see, it already started to feel not-so-reactive, and it will feel even less reactive once I fix the couple of mistakes I made here on purpose. You have probably noticed the first one: Any subscription left open after component destruction is a potential memory leak. So, let’s clear the subscription by storing it and calling its unsubscribe
method when the component gets destroyed.
There are alternatives to invoking theunsubscribe
method. We can pipe the stream through the takeUntil
operator and notify it with a Subject
. We can put the amazing @ngneat/until-destroy library into action, which eliminates the need for ngOnDestroy
. We can even use a service like the one ABP Angular UI supplies to collect subscriptions and avoid the destroy hook. Nevertheless, that doesn’t eliminate the essential drawback: Subscribing to an observable doesn’t feel reactive.
There is a second problem none of the above solves: change detection. This component works because zone.js will trigger change detection, and Angular will check this component every time a detection cycle runs. In a real-world app, this component, as is, may end up getting checked too many times. We could apply OnPush
change detection strategy to avoid this, but then the value emitted by our stream won’t cause a rerender unless change detection is triggered manually.
Well, the markForCheck
method of ChangeDetectorRef
doesn’t schedule a new change detection cycle, but it will register this component to be checked. So, the stream will emit a new value, prev
and next
will get updated, and during the next change detection cycle, our component will have a partial rerender. Yet, wouldn’t it be nice if you didn’t have to make an explicit change detection call?
Enter ng-observe
You must be rolling your eyes with weariness: “No! Not another subscription library!” Well, yes, this simple library subscribes to and unsubscribes from observables for you. However, it also gives you a reactive object and marks your components for change detection on every emitted value. This results in a reactive component/directive feeling. The library is called ng-observe, and I am a member of the NG Box team behind it.
Let’s see how our component looks when we apply ng-observe instead.
First, we have provided the OBSERVE_PROVIDER
at the component level. Then, with the OBSERVE
token, we have injected a function (ObserveFn
) in our component. Using this function, we can observe the emitted values and store them as Observed
objects. Referring to the value
property of these objects will always give us the current value, so we can easily build the logic for prev
and next
in two simple getters.
Furthermore, ng-observe allows you to combine count
and id
in a collection and thus get rid of theObserved
object. Here is how we can do that:
Lovely, isn’t it? There is a catch, though: destructuring the state
property works here because it happens inside a getter. If you want to obtain reactive properties derived from ng-observe collection props, you should convert them into Observed
objects. There are utility functions for that, and you can even get computed observed values.
Thanks to the toMappedValue
function, we have mapped the reactive state collection to theprev
and next
props. We don't need the getters anymore. We also don’t have to keep the collection as a prop. On the other hand, the bindings on the template changed to reflect the shape of the Observed
class.
Conclusion
The examples demonstrate ng-observe usage in a component, but the library works equally well in a directive because it is template-independent. Still, this is a side benefit. As a developer, the real advantage you get is how reactive the component or directive feels when you wield observable streams with it. We hope it will improve your DX too. You may find the playground here.
A final word, if I may: Please show us your support by sharing the library with others (and maybe giving us a star on GitHub). We are NG Box, and, as a team, this is our first but hopefully not last Angular library.
Thank you for reading. Have a great day!

More content at plainenglish.io