'Take once only when a boolean changes from false to true
I have multiple boolean properties which are false by default, but that may only be set to true at the start of the application. Should the property become true, I should take action once and then unsubscribe.
Here is a simple representation in a class. The default value of source
is false, and an on going interval will set it to true. I used an interval over a timeout here to ensure it only occurs once in my test.
export class MyCoolClass {
private source = new BehaviorSubject(false);
source$ = this.source.asObservable();
constructor() {
this.source$.subscribe((value) => {
console.log('my source', value);
});
window.setInterval(() => {
this.source.next(true);
}, 2000);
}
}
What is a clean way to handle this? A long time ago I wrote some annoying subscription:
export class MyCoolClass {
private source = new BehaviorSubject(false);
source$ = this.source.asObservable();
private mySubscription?: Subscription;
constructor() {
this.mySubscription = this.source$.subscribe((value) => {
if(value === true){
this.mySubscription?.unsubscribe();
console.log('my source', value);
}
});
window.setInterval(() => {
this.source.next(true);
}, 2000);
}
}
I feel as though I always end up with a subscription that I need to deal with.
Is there a cleaner way to achieve this?
Thanks 😊
EDIT
I believe this works, but it still seems a little bloated?
export class MyCoolClass {
private source = new BehaviorSubject(false);
source$ = this.source.asObservable();
constructor() {
this.source$
.pipe(
skipWhile(value => value === false),
first()
)
.subscribe((value) => {
console.log('my source', value);
});
window.setInterval(() => {
this.source.next(true);
}, 2000);
}
}
Solution 1:[1]
One way to simplify this would be :
export class MyCoolClass {
private source = new Subject();
source$ = this.source.asObservable();
constructor() {
this.source$
.pipe(
first()
)
.subscribe((value) => {
console.log('my source', value);
});
window.setInterval(() => {
this.source.next(true);
}, 2000);
}
}
Notably, making the BehaviourSubject into a Subject. BehaviourSubject specifically is for providing a default value to any subscribers. But in your case, you don't want a default value, infact you're skipping it entirely. So at this point, it would be simpler to simply move to a Subject and remove the skipping.
For a little more info on Subject vs BehaviorSubject (And ReplaySubject) here's a quick article : https://tutorialsforangular.com/2020/12/12/subject-vs-replaysubject-vs-behaviorsubject/
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | MindingData |