RxJS for Beginner Angular Developers: Fundamentals

Erik Slack
ngconf
Published in
11 min readMar 23, 2021

This is the second part to a series on RxJS for Beginner Angular Developers. Click this link to read part one which is an introduction to observables and why they’re important to learn how to use. The article you are now reading will teach you how observables are created, subscribed to, and operated on.

Just a note, you can watch a video re-imaging of this article by the author here.

RxJS for Beginner Angular Developers Part 2: Fundamentals by Erik Slack

Overview of Observables

Let’s do a quick recap on what observables are and how we use them.

Observables are a collection of values over time that we use to contain data retrieved asynchronously. They serve as a complete replacement for promises in our web applications and provide more benefits on top of it.

Using observables helps you in the following ways:

  • Your code becomes more reactive.
  • You can compose your observables in many useful ways.
  • They allow you to pass streams containing one or many pieces of data.
  • Use them without data if you want to send signals to other parts of your code, but don’t need to pass data.
  • You can subscribe to an observable in many different places at once.
  • You can terminate observables by completing them and you can unsubscribe from them.

It’s important to remember that observables won’t do anything until you subscribe to them. I’ll show you how to subscribe to observables later in this article.

beautiful field of green 4 leaf clover
Photo by Yan Ming on Unsplash

4 Ways to Create Observables In Angular

There are several ways to create observables in Angular:

  1. Using one of several features in Angular that generate observables.
  2. Using a library that works with Angular.
  3. Using an RxJS creation operator.
  4. Using an RxJS subject.

Let’s dive into each of these and see how to make use of these.

Angular Features Generate Observables

In the last article of this series we discussed how RxJS came about in Angular 2 and beyond. Thanks to those early adopters and pioneers of RxJS it has advanced and been improved in significant ways since then. When Angular needs to return most pieces of data it does so using Observables. Here’s an incomplete list of features that do this:

  • HttpClient: GET, POST, DELETE, etc.
  • Routing: RouterEvents, Router, ActivatedRoute
  • Events: FromEvent, EventEmitters
  • Angular Material: Dialogs, various CDK features, etc.

Libraries That Work With Angular

There are many third-party libraries available in the npm ecosystem for Angular development. Two really notable ones are NgRx for reactive, central state and Angular Fire, an SDK for working with Firebase. Both of these third-party libraries generate observables. Many other libraries also generate observables — after all that is the Angular way of doing asynchronous things and it’s also the Angular way of passing data around.

Shows how to open a dialog with Angular Material.
Angular Material Dialog .open() .afterClosed() returns an observable!

RxJS Creation Operators

Creation operators are functions that create observables with predefined behavior. You usually use these in conjunction with pipeable operators — the other kind of operators. One of the simplest being the of(myValue) operator which takes any value and turns it into an observable. We’ll talk more about both kinds of operators later in this article.

RxJS Subjects

RxJS subjects are basically observables that have three extra methods: next(), error(), and complete(). You can create a subject like this:

private ngUnsubscribe = new Subject()
Creating a new subject is easy!

You can create an observable from a subject by calling .asObservable() on it.

This allows you to completely control what gets emitted in an observable stream, how you handle errors, and when that stream should terminate.

There are different kinds of subjects: Subjects, BehaviorSubjects, ReplaySubjects, and AsyncSubjects. More often than not, you’ll be using regular Subjects or BehaviorSubjects. The main difference between Subjects and BehaviorSubjects is that with BehaviorSubjects you always have a value contained in them. You create them with a value and anything that subscribes to that value will get the latest value stored in it.

new BehaviorSubject(initialScreenSizes); screenSizeSubject.asObservable()
Subjects can generate an observable by using .asObservable()

With subjects you don’t have to have a value in it. Often times you’ll create subjects to send signals to subscribers, as opposed to passing data through them.

Operators

Now that you’ve learned how to create observables in RxJS, let’s discuss how to use operators to manipulate them in various ways.

There are two kinds of operators: creation operators and pipeable operators.

Creation Operators Continued

There are all kinds of creation operators. Remember, creation operators are functions that create observables with predefined behavior. Earlier in this article I gave you an example of one creation operator. Here’s another commonly-used creation operator called combineLatest().

CombineLatest Operator takes two or more observables and combines the latest values emitted by each into a single observable stream.

combineLatest([this.campaigns$, this.notes$])
Use combineLatest to combine the streams of multiple observables.

Another super handy creation operator is fromEvent().

fromEvent(document, ‘click’)
Use fromEvent() to generate an observable from a DOM event listener.

To round out your basic knowledge of creation operators I have to introduce you to of(). Of Operator creates an observable out of any value.

of(someValue)
Use of() to make observables of absolutely anything! That’s a neat party trick.

The main purpose of this operator is to make it easy to generate observables when you require one for use with a library. It’s also handy for unit testing logic that uses observables.

Pipeable Operators

There are all kinds of pipeable operators. Pipeable operators are functions that manipulate an existing observable stream somehow. To use one you must call .pipe() on an observable and then give it operators for arguments. Notice how multiple operators can be chained within the same pipe. It’s a very readable syntax for such a powerful technique!

Shows how to use filter and take operators.
Filter and take are being used together in this pipe.

The Filter Operator is a fantastically useful one that will filter out anything emitted that doesn’t cause the filter’s handler function to return true.

The Take Operator is primarily used for triggering logic downstream only once. It’s also helpful for automatically unsubscribing, which I’ll address later in this article.

There are many, many operators to cover, so for now I’m just going to explain these last two: Map Operator and SwitchMap Operator.

The Map Operator is your go-to for transforming your observable’s value to something different. If you want to run some calculations on some data in your observable every time it emits then Map is your operator. It’s used very much like the prototypical map method for arrays in JavaScript.

Shows how to map an observable and then map the array value inside it.
Don’t confuse RxJS map operator for the array map method. Mapping an observable and mapping or filtering the array contained therein is a common use case.

The SwitchMap Operator should be your first choice of operators when you want to swap — mid-stream — what observable you’re listening to. This is a really common thing to do. There is a lot more to SwitchMap Operator, but this is the most common use case: I want to pay attention to some Observable A, and once I get the emission I want from it I want to suddenly watch this other Observable B. It could be a httpClient.get(this.myUrl) or it could be an observable you’ve created.

There are 3 other operators that are similar to SwitchMap Operator because they take in an observable and emit a different observable. They are MergeMap, ConcatMap, and ExhaustMap. In most cases you’ll want to default to SwitchMap, but each has important differences to consider in how they process the new/inner observables.

For the next article in this series, I will go into further detail on these four and I’ll also cover many other commonly-used operators in RxJS.

Subscribing

There’s no point in learning how to use observables and operators if you never learn how to subscribe to them! Remember that observables don’t do anything until they’re subscribed to.

Subscribing to an observable is the way to make logic happen every time the observable emits. If your observable emits one time like with a typical http request, then your logic in the subscribe’s callback function will trigger once. If your observable emits many times — like when you create an observable from a click event listener using fromEvent()— then that same logic in the subscribe method’s callback function will trigger every time the observable emits. In the example it would be every time the user clicks on something.

A common use case for subscribing to an observable is because you want to unwrap the value it contains. If you want to display the latest value emitted by an observable you have to subscribe to it.

Shows subscribing to an observable in your component’s class.
Subscribe to trigger some logic every time the observable emits.

A subscription is returned when you call .subscribe() on an observable. You can store that subscription in a variable if you want to, but it’s not necessary. The main reason to do that is if you wanted to call unsubscribe() on it to cancel your subscription. But there are better ways to handle unsubscribing.

The second way to subscribe to observables in Angular is by using the built-in Async Pipe. If you reference your observable in your HTML template then you can use a pipe with it to automatically subscribe to the observable and return the latest unwrapped value. Using Async Pipe is arguably the best way to get the value out of an observable.

Shows using async pipe in template.
Async pipe is #1 way to unwrap observables’ values for templates.

You should generally use Async Pipe whenever you need the value of an observable to display in your templates and when you want to pass its value to a component via property binding.

Character punches big blow-up clown and it rocks back and knocks him over.
Ha ha ha.

When you’re first learning RxJS it’s extremely tempting to subscribe to all of your observables and set their values as second properties on the component class. Avoid doing this! It’s a code smell to manually subscribe to an observable in your class just so you can store the value of the observable in a property.

Unsubscribing

Subscribing allows us to get the values out of an observable, but it comes with a consequence. That consequence is memory leaks that we need to handle.

Memory leaks in bright green and bright red.
But that’s the point: we are aware and we eliminate all leaks.

If we subscribe, then we must also unsubscribe. The ability to cancel subscriptions is the gold nugget that Ben Lesh originally proposed made RxJS a better default for async than promises. In RxJS you can cancel, let me show you how.

First way: .unsubscribe() is the worst possible way to unsubscribe from your subscriptions. Technically it works. You can store references to all of your subscriptions and then manually call .unsubscribe() on all of them in your ngOnDestroy() component lifecycle hook. I used to do this before I learned more about the other much better options: Take Operator, TakeUntil Operator, and Async Pipe.

Shows unsubscribing 5 times in the ngOnDestroy lifecycle hook.
Very messy! This is why we don’t unsubscribe manually.

Async Pipe is fantastic for all of the reasons I mentioned in the above Subscribing section, but there’s one really cool feature of it that I intentionally left out. That feature is that it handles unsubscribing automatically, so you never have to.

Shows how to use async pipe in your templates to unwrap observable value.
Default to using the async pipe if you’re using an observable in your template.

The Take and TakeUntil Operators are more useful for those times when you want to trigger a piece of logic based on events sending data through your observable stream. Use take(1) when you want to unwrap the value of an observable and use it for some one-and-done logic.

Shows how to use take(1) to get a value once from an observable stream.
For one-and-done subscriptions use take(1).

On the other hand, if you want to stay subscribed until the browser gets closed or the user navigates to a different page that doesn’t include your component anymore you should use takeUntil(this.unsubscribeAllSubject).

First, create a new subject in a class property called unsubscribeAllSubject or ngUnsubscribe — basically you should always name it consistently so you know what it is when you see it. Next, add ngOnDestroy() {} lifecycle hook to your component. Inside of its scope block call next and complete on your subject.

ngOnDestroy() {
this.unsubscribeAllSubject.next();
this.unsubscribeAllSubject.complete();
}

Finally, add a takeUntil(this.unsubscribeAllSubject) operator to your observable in a pipe before your subscribe to it.

Shows how to use a subject and ngOnDestroy to terminate observables.
For long lived subscriptions use TakeUntil() with a subject.

Now when your component is destroyed it will automatically free up that memory for you.

Conclusion

Congratulations on making it this far! You now have all of the necessary knowledge to get dangerous with RxJS. You show now understand how to create, use, change, combine, and cancel observables.

Next Steps

RxJS is a big subject! There’s a lot more to learn beyond the fundamentals. One excellent source for further learning is the ngconf publication where this article has been published. Subscribe and keep growing your skills!

More Next Steps

In that same video you can learn from another ngconf Champion, Michael Madsen, about styling and triggering logic by responding to device sizes — without needing media queries — using RxRs.

Both of these concepts require at least some knowledge of RxJS and can improve your software development with Angular.

Thanks for reading!

If you liked this article, please give me some claps — you can give 50 you know! That helps me celebrate my accomplishment of successfully teaching others how to do this really cool thing. You can also follow me on Twitter at @erik_slack. I invite you to dm me if I spoke incorrectly or you see a way to improve this article. Thank you for reading and please share it and stay tuned for the following two articles in the series!

Now that you’ve read this article and learned a thing or two (or ten!), let’s kick things up another notch!

Take your skills to a whole new level by joining us in person for the world’s first MAJOR Angular conference in over 2 years! Not only will You be hearing from some of the industry’s foremost experts in Angular (including the Angular team themselves!), but you’ll also get access to:

  • Expert panels and Q&A sessions with the speakers
  • A friendly Hallway Track where you can network with 1,500 of your fellow Angular developers, sponsors, and speakers alike.
  • Hands-on workshops
  • Games, prizes, live entertainment, and be able to engage with them and a party you’ll never forget

We’ll see you there this August 29th-Sept 2nd, 2022. Online-only tickets are available as well.
https://2022.ng-conf.org/

--

--

Erik Slack
ngconf
Editor for

Husband | Dad | Dev | He/Him (cis) GDE in Angular | SE Technical Lead at Cisco | #BlackLivesMatter