TL;DR: check out this stackblitz
Understanding the concept of Observables is fairly straightforward. Using them to get something real done, when you are first learning, is difficult.
The learning curve is well documented, and even great attempts to flatten the curve have been made.
Even with all the resources out there, and what I thought was a pretty good conceptual understanding of how Observables worked, I had trouble connecting the pieces to implement something real world and simple: load data remotely, populate a <select>
with the data.
Subscribing to an Observable is easy. Making an observable with trivial, self contained data is also easy: const myObservable = of(1, 2, 3)
But in the problem I was trying to solve, my data was being loaded someplace else, and asynchronously. I wanted to be in control over WHAT and WHEN data was put on the observable stream and MULTIPLE consumers.
Subject to the rescue
A Subject is like an Observable, but can multicast to many Observers. Subjects are like EventEmitters: they maintain a registry of many listeners.
Read this a few times and it conceptually, makes sense right? After reading the Subject docs I knew that this would solve my “I want to be in control of when and where” problem. However, I still wasn’t super clear how I could solve my problem cleanly. I’m a big async
and await
guy. I knew I could solve my problem in 10 lines or less using them. Subject
s at this point, looked to be much much longer.
Don’t give up, the payoff is worth it
After lots of tinkering and reading I was getting frustrated. I could get it to work, but I didn’t like how much code was needed nor how much complexity it was adding over just using async/await
to solve my problem. Being able to have multiple subscribers of my data was the carrot that kept me going. I knew there HAD to be a clean way to pull it off. There was..
The demo
https://stackblitz.com/edit/angular-swt3tz
You only need to open two files: app.component.ts
and app.component.html
. The inline comments should make it pretty self explanatory, however I’ll touch on a few things.
this.multicastBreweries$.next(b);
inside getOptions()
is the way I control WHAT and WHEN the data I pulled remote&async is put on the stream. Anyone subscribed to this data source, gets called and can do whatever they want with the data.
this.brewOptions$ = this.mapBreweriesToOptions(this.multicastBreweries$);
in ngOnInit()
. This subscribes to the data (via .pipe()
) , and transforms it (via rxjs.operators.map) from Brewery data to a data format the <select>
needs. The trickiest part is converting the type using the RxJS map operator. 99% of the examples you will see online use map with no template/generic specification. Said anther way, the examples out there don’t need to convert the data from one type to another. The map<Brewery[], SelectOption[]>
shows you how. It is pretty easy, and makes sense once you see an example.
Thats it
My blabbering above may have confused you more, but hopefully the working example makes it clear in your mind.