I am currently saving values when a user changes an input field. I don't want to save the value each time a new character is entered so I'm using the rxjs debounceTime to save after 3000ms (just an example) of no changes.
this.subscription.add(this.form.controls.inputControl.valueChanges
.pipe(debounceTime(3000))
.subscribe(value => {
// execute HTTP call with value
}));
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
If the user changes the value and OnDestroy gets called before the 3000ms timer is reached, the call won't get executed no more. I was wondering if there was a way to cancel the active timer and execute all remaining observables before destroying the component.
EDIT: Another option could be that the user gets a warning when there are unsaved changes. Like the way google calendar does when adding a new task and leaving the page
const destroyed = new Subject();
const isTimerActive = new BehaviorSubject(false);
const stop$ = combineLatest(destroyed, isTimerActive)
.pipe(
filter(([isDestroyed, isTimerActive]) => isDestroyed && !isTimerActive)
);
src$.pipe(
debounce(
() => (
// Now if the component is destroyed, it will not unsubscribe from this stream
isTimerActive.next(true),
timer(/* ... */)
)
),
switchMap(v => makeRequest(v)),
// If the component is destroyed, then after sending this
// the stream will be unsubscribed
tap(() => isTimerActive.next(false)),
takeUntil(stop$)
).subscribe(/* ... */)
ngOnDestroy () {
this.destroyed.next(true);
this.destroyed.complete();
}
It's important to note that the timer is declared inactive(isTimerActive.next(false)
) only when we've finished all the tasks that involve the value emitted after the delay.
This is because if destroyed
is true
and we immediately do isTimerActive.next(false)
, the unsubscription will happen synchronously, meaning that you won't be able to do anything else with that value.