208. Module Introduction
The text says the section will dive deeper into RxJS by explaining observables (noting that subjects are a type of observable). It will cover what observables are, how to create and use them, how to use observable operators to transform/manipulate emitted values, and it will compare observables with signals. It ends by posing the question: “What exactly are observables?”
209. What Are Observables & What Is RxJS
Observables in Angular aren’t an Angular-only feature—they come from the RxJS library, which Angular uses internally. An observable is an object that creates and manages a stream of data over time. Angular features can provide observables (data streams), but to understand them, you can also create observables yourself.
210. Creating & Using an Observable
-
A simple Angular starter project is used to experiment with RxJS observables (not building a full demo app).
-
Recap: BehaviorSubject is a special RxJS “subject” that you manually emit values into; it’s an observable-like stream used to broadcast values to subscribers (somewhat comparable to Angular Signals, with differences to be discussed).
-
Observables can also be created without subjects using RxJS creation functions, e.g.
interval(). -
In
AppComponent, implementOnInitand create an observable viainterval(1000), which automatically emits incrementing numbers every second. -
To make an observable actually run, you must subscribe; without subscribers, RxJS won’t emit values.
-
subscribe()accepts an observer with up to three handlers:next(per value),error, andcomplete(often never called forinterval()since it runs indefinitely). The example only usesnextto log values. -
Important best practice: store the subscription and unsubscribe on component destroy to prevent memory leaks. The example uses Angular’s
DestroyRef(injected viainject) to run cleanup and callunsubscribe()when the component is removed.
211. Working with RxJS Operators
The lecture explains that interval() can create an observable that
emits values every second, useful for periodic tasks like polling an
HTTP endpoint or updating UI/animations.
It then introduces RxJS operators, which are functions used to
transform or manipulate values emitted by an observable. Operators are
added via pipe() (called before subscribe()), and an observable
won’t emit anything unless there is at least one subscription.
As an example, the map operator (imported from RxJS) is added to an
interval stream. map takes a function that runs on every emitted
value and returns a transformed value (e.g., doubling the emitted
number). Multiple operators can be chained in pipe().
Key takeaway: operators are a central RxJS feature that enable transforming observable values, and they’re an important concept (and a difference compared to signals).
212. Working with Signals
-
Recap of Observables: created an observable with
interval()and added operators; observables typically have an automatic data source that emits values over time. -
Recap of Subjects: subjects are a special kind of observable where you both subscribe and manually emit values (you control when new values are produced), and they can be subscribed to in multiple places/components.
-
Introduction of Angular Signals (built into Angular, not from RxJS): the lesson shifts to using a signal and comparing it to observables/subjects, including converting between signals and observables.
-
Implementation shown:
-
Add a button click handler
onClick()via(click)="onClick()". -
Create a signal
clickCount = signal(0)(imported from@angular/core). -
Increment the signal on each click using
this.clickCount.update(prev => prev + 1). -
Display the signal in the template by referencing
clickCount. -
Create an
effect()(also from@angular/core) that re-runs wheneverclickCountchanges, logging: “Clicked button X times”. -
Comment out the interval observable logs to reduce console noise.
-
-
Result: initial state logs “Clicked button 0 times”; each click updates both the UI and the console via the signal/effect.
-
Transition question: signals behave like a data stream you manually “push” updates into (similar to a subject), prompting a discussion of differences and similarities between signals and observables.
213. Signals vs Observables
Signals and RxJS observables/subjects can look similar and sometimes solve the same problems (e.g., sharing state between components), but Angular signals are newer while RxJS was historically used for state sharing and subscription management.
Key differences highlighted:
-
Observables = values over time (streams): You must subscribe to receive emitted values, and emissions typically happen asynchronously. They’re well-suited for events and data sources like
interval(). Many observables are lazy and only start producing values when there’s at least one subscriber. -
Signals = value containers: They hold a current value (with an initial value) that you can read synchronously at any time without subscribing. Reactivity happens automatically when signals are read in templates,
computed, oreffect. They’re especially good for application state that starts with an initial value and changes over time.
Using signals for something like an interval is possible (manual
setInterval, updating a signal, then deriving values with a computed
signal), but it can be more code, requires manual cleanup, and will
run even if nothing consumes it, unlike a typical observable.
Both approaches remain useful depending on the situation and preference, and Angular provides tools to convert between observables and signals (observable→signal and signal→observable), which is the next topic.
214. Converting Signals To Observables
You can convert between Angular signals and RxJS observables rather than choosing only one approach.
-
To listen to a signal via RxJS, use Angular’s
toObservablefrom@angular/core/rxjs-interop. -
Pass the signal itself (don’t call/execute it) into
toObservable, e.g. convertclickCountinto an observable. -
toObservableshould be used in places where DI is allowed (e.g. constructor or as a property initializer). -
A common convention is naming observable properties with a trailing
$, e.g.clickCount$. -
After conversion, you can
subscribe()(e.g. inngOnInit) and handle new values innext; TypeScript infers the emitted type (herenumber). -
As with any subscription, store it and unsubscribe (e.g. in
ngOnDestroy) to avoid leaks. -
Updating the original signal still works; each update also emits a new value through the observable created by
toObservable, allowing logging/reacting via RxJS on each click.
215. Converting Observables To Signals
-
Shows converting an RxJS
interval(1000)observable (named with$) into an Angular Signal usingtoSignal()from@angular/core/rxjs-interop, typically when defining class properties or in the constructor (where injection is possible). -
The resulting Signal updates whenever the observable emits and can be used like any other Signal: in templates,
effect(), orcomputed(). -
Key difference: observables (like
interval) have no initial value, while Signals always do. Therefore, a Signal created viatoSignal()starts asundefinedunless configured. -
You can provide an explicit initial value by passing a second argument to
toSignal()with a config object, e.g.{ initialValue: 0 }, so the template shows0immediately. -
toSignal()automatically manages subscription cleanup when the hosting component is destroyed. This can be disabled with{ manualCleanup: true }, in which case you must handle disposal yourself.
216. Deep Dive - Creating & Using A Custom Observable From Scratch
-
Demonstrates how to create an RxJS
Observablefrom scratch by instantiating theObservableclass (instead of using creation operators likeinterval), explaining that built-in operators use this class internally. -
The
Observableconstructor takes a function that RxJS runs when someone subscribes. This function receives a subscriber/observer object. -
Inside the constructor function, you control emissions by calling:
-
subscriber.next(value)to emit values (which triggers the subscription’snexthandler), -
subscriber.complete()to finish the stream (triggering the subscription’scompletehandler and ending emissions), -
subscriber.error(err)to emit an error (triggering the subscription’serrorhandler).
-
-
Example implementation uses native JavaScript
setIntervalto emit a value every 2 seconds (and optionally logs"Emitting new value…"), then subscribes inngOnInitto print received values. -
Shows how to stop an infinite observable: track a counter, clear the interval via
clearInterval(intervalId), callcomplete(), and optionally handle completion in the subscriber with acompletecallback (e.g., logging"COMPLETED!"). -
Concludes with the key concept: subscriptions define what happens when events occur, while the Observable’s constructor logic defines when those events are emitted (next/complete/error), which is essentially how Observables work “under the hood.”