Post

Simplifying Angular Templates with combineLatest in NgRx

When working with Angular and NgRx, a common challenge is effectively managing and combining state selectors in a clean and readable way. The combineLatest function offers a powerful solution to this problem, especially when paired with Angular’s async pipe and ng-container. This approach allows you to create more streamlined and maintainable templates, improving both readability and performance.

Understanding combineLatest

The combineLatest function in RxJS, which NgRx relies on, is used to combine multiple observables into one. When using it with NgRx selectors, it allows you to combine multiple pieces of state into a single observable stream, which you can then subscribe to in your components.

Here’s a basic example:

1
2
3
4
data$ = combineLatest([
  sample1: this.#store.select(sampleSelector1)),
  sample2: this.#store.select(sampleSelector2))
])

In this example, data$ is an observable that emits an object containing sample1 and sample2 whenever either selector emits a new value. This combined observable can then be used directly in your Angular template.

Leveraging ng-conteiner and the async Pipe

One of the most effective ways to use combineLatest in your Angular template is by starting with ng-container and the async pipe. This approach not only simplifies your template but also improves performance by reducing the number of async subscriptions.

Here’s how you can do it:

1
2
3
4
<ng-container *ngIf="data$ | async as data">
  <div></div>
  <div></div>
</ng-container>

The Advantage

Using combineLatest together with ng-container and the async pipe offers several benefits:

Single Subscription: By using combineLatest, you only need one async pipe in your template, which reduces the number of subscriptions and simplifies your template logic.

Clean Template: The ng-container directive allows you to directly access all the combined state selectors within a single data object, keeping your template concise and easy to read.

Improved Performance: Fewer subscriptions mean less overhead, leading to better performance, especially in complex components.

Reduced Boilerplate: Instead of managing multiple *ngIf="observable$ | async as value" directives, you only manage one, which reduces the amount of boilerplate code in your templates.

Putting It All Together

Consider a component that displays user details and preferences from two different selectors. Without combineLatest, your template might look something like this:

1
2
3
4
5
6
7
8
9
10
11
<div *ngIf="user$ | async as user">
  <div></div>
</div>
<div *ngIf="preferences$ | async as preferences">
  <div></div>
</div>
By using combineLatest, you can simplify this to:
<ng-container *ngIf="data$ | async as data">
  <div></div>
  <div></div>
</ng-container>

This approach not only looks cleaner but also scales better as your component grows in complexity.

Conclusion

Using combineLatest in combination with ng-container and the async pipe in Angular templates provides a more efficient, cleaner, and maintainable way to manage state selectors from NgRx. By adopting this pattern, you can reduce the complexity of your templates, leading to code that’s easier to read, write, and maintain. Give this approach a try in your next Angular project and experience the difference it can make in your codebase!

This post is licensed under CC BY 4.0 by the author.