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, implement OnInit and create an observable via interval(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, and complete (often never called for interval() since it runs indefinitely). The example only uses next to log values.

  • Important best practice: store the subscription and unsubscribe on component destroy to prevent memory leaks. The example uses Angular’s DestroyRef (injected via inject) to run cleanup and call unsubscribe() 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 whenever clickCount changes, 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, or effect. 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 toObservable from @angular/core/rxjs-interop.

  • Pass the signal itself (don’t call/execute it) into toObservable, e.g. convert clickCount into an observable.

  • toObservable should 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. in ngOnInit) and handle new values in next; TypeScript infers the emitted type (here number).

  • 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 using toSignal() 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(), or computed().

  • Key difference: observables (like interval) have no initial value, while Signals always do. Therefore, a Signal created via toSignal() starts as undefined unless 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 shows 0 immediately.

  • 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 Observable from scratch by instantiating the Observable class (instead of using creation operators like interval), explaining that built-in operators use this class internally.

  • The Observable constructor 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’s next handler),

    • subscriber.complete() to finish the stream (triggering the subscription’s complete handler and ending emissions),

    • subscriber.error(err) to emit an error (triggering the subscription’s error handler).

  • Example implementation uses native JavaScript setInterval to emit a value every 2 seconds (and optionally logs "Emitting new value…​"), then subscribes in ngOnInit to print received values.

  • Shows how to stop an infinite observable: track a counter, clear the interval via clearInterval(intervalId), call complete(), and optionally handle completion in the subscriber with a complete callback (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.”