Some Tips for Working with Angular — From a Frontend Developer — Part 2.
Let’s continue the series on tips for working with Angular — the most challenging framework.
As always, let me know in the comments if you find this interesting to read or if there’s anything I can improve. I’d love to hear your feedback!
Note: These tips require prior knowledge and experience with Angular. I will not dive deep into RxJS or other fundamental concepts.
Get and Use the Previous Value of a BehaviorSubject
There are times when we need to retrieve the previous value of a BehaviorSubject
for calculations. For example, increasing the current value by 1. There are two ways to do this:
1/ Using the the getValue()
function of behavior subject.
For this approach, you can use this like:
protected increaseVal1() {
this.var1$.next(this.var1$.getValue() + 1);
}
This approach is straight-forward and easy to implement. However, in some projects, accessing the value property of a BehaviorSubject
is forbidden, meaning you cannot use the getValue()
function freely. There are specific reasons for this, but I won’t dive deep into them in this article. If you're interested, I recommend researching it further on Google.
So, if we can’t use getValue()
, how can we achieve this?
2/ Using observables
With a little RxJS magic, you can achieve the same result using observables:
protected increaseVal1() {
this.var1$
.pipe(
first(),
tap((v) => this.var1$.next(v + 1)),
)
.subscribe();
}
The first operator ensures that we only take the initial value from the stream and then unsubscribe immediately, preventing an infinite loop or memory leaks. Therefore, using first()
or take(1)
is essential here.
This approach does not violate any best practices or project rules, so I often use it in my projects. Hope this helps you as well!
Use the debounceTime
operator when a value changes multiple times, but you only need the source to emit once.
Sometimes, in our projects, we encounter situations where we need the source to emit only once, even if the value is updated multiple times. For example, consider the following component:
import { Component, OnInit } from "@angular/core";
import { BehaviorSubject, first, skip, tap } from "rxjs";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"],
})
export class AppComponent implements OnInit {
protected readonly var1$ = new BehaviorSubject(100);
ngOnInit(): void {
this.var1$
.asObservable()
.pipe(
skip(1),
tap((val1) => console.log({ val1 })),
)
.subscribe();
}
protected increaseVal1() {
this.var1$
.pipe(
first(),
tap((v) => this.var1$.next(v + 1)),
)
.subscribe();
}
protected changeValue1() {
this.increaseVal1();
this.increaseVal1();
}
}
<div>
<p>Value 1: {{ var1$ | async }}</p>
<button (click)="changeValue1()">Increase Value 1</button>
</div>
And the UI for this code looks like this:
When I click the “Increase Value 1” button, the logs are:
As you can see, the tap operator is called twice because the increaseVal1
function is executed twice synchronously within the changeValue1
function.
In some cases, you might want the tap operator to execute only once, using the latest value, even if the function that changes the value is called multiple times.
How can we achieve that? Simple — just add the debounceTime(0)
operator beforehand.
ngOnInit(): void {
this.var1$
.asObservable()
.pipe(
skip(1),
debounceTime(0),
tap((val1) => console.log({ val1 })),
)
.subscribe();
}
Now, when you click the button, the logs will include only the latest value, meaning the tap operator is executed only once.
When you add debounceTime(0)
, RxJS delays the emissions until the current event loop cycle ends, so:
- Both
pipe(...).subscribe()
calls happen in the same JavaScript tick. - Since
debounceTime(0)
defers execution, both calls collapse into one before emitting a value. - As a result,
console.log
in tap operator only run once. - In real-world projects, this scenario might be rare, but if you ever encounter it, you can use this approach to handle it effectively.
And that’s all for blog #2 about the Angular tips! I hope you found these tips helpful. See you in my next blog!
Top comments (0)