Why RxJS alone doesn't guarantee declarative code

Simply pulling in RxJS doesn't automatically make your code declarative. In fact, the moment you call subscribe(), you've already shifted into imperative territory.

Being declarative with RxJS requires conscious effort.

Step 1: Set up the service

First, we'll build a service and define a variable named todo$ inside it.

The dollar sign follows a common naming convention that signals the variable holds an Observable, not the data itself.

The data retrieved from the URL will be

But if you run this as-is, you'll see no output. The console will remain empty.

Step 2: Bind the observable to a component variable

Now we switch to the component.

The crucial part is line 10:

data$ = this.todoService.todo$;
Enter fullscreen mode Exit fullscreen mode

We create a local property called data$ and assign the service's observable to it so the component can reference it.

Notice that we haven't instructed Angular to subscribe or unsubscribe. There's no observer in sight either. This is where the declarative approach really pays off.

Our only intention is to render the data in the template. How Angular makes that happen is irrelevant to us.

Again, if you test this now, nothing will appear. Both the console and the template will stay blank.

That's expected — we haven't actually told Angular what we want it to do yet.

Step 3: Leverage the async pipe with the local variable

Let's move over to the template and define the goal: display the object's title in the template once the data arrives.

We achieve this with the async pipe. This pipe takes care of subscribing and unsubscribing for us, as demonstrated here:

// app.component.html
<div *ngIf="data$ | async as data">
  {{ data.title }}
</div>
Enter fullscreen mode Exit fullscreen mode
  1. First, we bind to data$ from the component.
  2. Second, the async pipe handles the subscription and unsubscription automatically.
  3. Third, we use as data to create a local variable that holds the value emitted by the observable.
  4. Finally, that variable can be used throughout the template, just like any other property.

For a deeper dive with a side-by-side comparison of this approach versus the conventional imperative style, check out RxJS Declarative Pattern in Angular on Medium.

Feel free to share your thoughts!