RxJS in Angular – Single Result Data Streams and Async Pipe

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 article:

RxJS in Angular – Single Result Data Streams and Async Pipe
Yannick Baron is architecture consultant at Thinktecture and focuses on Angular and RxJS.

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.

https://stackblitz.com/edit/angular-ci9trw?file=src/app/app.component.ts

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.

Free
Newsletter

Current articles, screencasts and interviews by our experts

Don’t miss any content on Angular, .NET Core, Blazor, Azure, and Kubernetes and sign up for our free monthly dev newsletter.

Related Articles
.NET
Roslyn Source Generators: Logging – Part 11
In previous part we lerned how to pass parameters to a Source Generator. In this article we need this knowledge to pass futher parameters to implement logging.
29.08.2023
.NET
Roslyn Source Generators: Configuration – Part 10
In this article we will see how to pass configuration parameters to a Roslyn Source Generator to control the output or enable/disable features.
29.08.2023
.NET
Roslyn Source Generators: Reduction of Resource Consumption in IDEs – Part 9
In this article we will see how to reduce the resource consumption of a Source Generator when running inside an IDE by redirecting the code generation to RegisterImplementationSourceOutput.
29.08.2023