In the first and second part of this small series, we have discussed implementations that have flaws and can introduce side-effects to our data flow. We have learned how combining our streams and modeling our our data flow to yield a single result helped with solving the introduced problems.

In this third part of the series we want to talk about another advantage when modeling our streams in this manner, specifically in the context of an Angular application.

Composing data streams to yield a single result and leveraging the async pipe

Similar to the previous posts, we want to combine streams to retrieve from multiple entities. This time however, we make sure that the final product of our stream is our view model.

For this example we keep it rather simple and combine the request for a user object with the request for a list of roles in our system, so we can fill the view with a nicer representation than just a role id.

// Stream that emits an user object when the userId route param changes
const user$ = this.route.params.pipe(
  switchMap(({ userId }) => requestUser(userId)),
);

// Stream that emits a list of all role objects once
const roles$ = requestRoles();

// Combine both streams
const userAndRoles$ = combineLatest(user$, roles$);

// Transform combined result into UserView model
this.userView$ = userAndRoles$.pipe(
  // Create a UserView object containing the user's properties and its roles
  map(([user, roles]) => ({
    ...user,
    roles: resolveUserRoles(user, roles)
  }))
);

In the implementation above, we create two streams. One to request and emit a new user object when the userId route param changes, and one to emit a list of all roles once (technically, we could emit live updates of roles, too). We use the combineLatest operator which combines the latest emit of the given streams into a single emit. In our case this serves two purposes. First, once the user$ emits again, which happens when we change the route accordingly, the same pipeline runs and the view will be updated with the new user and its respective roles. Additionally, we cannot display the view until the roles are received. combineLatest will hold back on its emit, until both streams have produced a value.

Finally, we can now use the userView$ stream in our template and subscribe to it via the async pipe. This way we do not even have to handle subscriptions. Another advantage of using the async pipe is that we can easily switch our change detection strategy to OnPush as the template will only need to be updated when our stream emits.

<dl *ngIf="userView$ | async as userView">
  ...
</dl>

You can see this live on stackblitz.

Conclusion

In this series so far, we briefly discussed how combining our streams to yield a single result helps us eradicate potential side-effects. We now illustrated how following this principle can make working with streams in Angular applications easier, as the async pipe implicitly handles subscriptions for us. Ultimately, this comes with performance improvements, as we can make use of the OnPush change detection strategy.

Related Articles

rxjs
RxJS in Angular - Antipattern 2 - Stateful Streams
This is the second part of a small series, in which I want to share some pitfalls we discovered multiple times in code reviews over the years, as well a few patterns we identified as helpful. In the first part we discussed how nesting subscriptions can be harmful. Stateful…
Yannick Baron
rxjs
RxJS in Angular - Antipattern 1 - Nested subscriptions
Working on numerous Angular projects over the past couple of years, it has become evident, that a lot of developers still have a hard time working with RxJS which finds its use in Angular. While RxJS is a very powerful tool, it comes with a lot of operators and a whole paradigm…
Yannick Baron
web components
Creating Web Components With Modern SPA frameworks - Angular, React, and Vue.js
You might have read the article series about Web Components in which we talked about the advantages and disadvantages of Web Components in detail and how they are integrable in modern SPA frameworks. This article focuses on how you can create Web Components using a modern SPA…
Manuel Rauber
angular
Adobe XD, Storybook & Angular in Action - From Paper Sketch to a Running Application
In this article, I will show you how to design and develop application components for a SPA. We will start of from a paper sketch, head over to a designer tool, like Adobe XD, followed by an interactive testing environment, like Storybook, to finally result in a running Angular…
Konstantin Denerz