Reputation: 43
I will need some help with a use case I'm stuck right now:
I'm implementing an autosaving feature in Angular 6 and Ngrx for a dialog 'form' (this case doesn't use but it changes the state with some actions when clicking) with the following conditions:
If any element is changed (selected), it triggers the timer of 30s, the user can change as many as he wants during that time and when the timer finish, emit the state. (If I change multiple inputs between those 30s, there will be only one emit)
If the dialog is closed before the 30secs and data were changed on the form, it must be saved right away.
Currently, for the first case I have this observable:
this.configuration$ = this.store.pipe(select(getTopicsList));
this.configuration$
.pipe(
distinctUntilChanged(),
debounceTime(30000),
skip(1),
).subscribe(res => this.saveCurrent());
Note: the skip(1)
is only to skip the first emit when the component is being initialized
For the second I have and Subject converted to an Observable to emit an event every time the dialog is closed:
this.close$ = this.closeStream.asObservable();
With Observable operators, there is any way to combine both and condition the emit if changes in the this.configuration$
observable had been made?
I'm not that strong in observables but maybe I'm overthinking and there is an efficient solution. It will be awesome in someone can give me a head with it. Thank you very much.
Upvotes: 4
Views: 2985
Reputation: 21161
You could use race
but only after the form has changed.
Basically, every time the form changes, you want to save it either after a certain delay or once the user closes the modal, whatever comes first.
Like this, if instead of saving the form when the modal is closed you want to add a Save button, it would only be saved once until it changes again.
It should be something like this:
const {
Subject,
of,
race
} = rxjs;
const {
distinctUntilChanged,
skip,
switchMap,
delay,
take
} = rxjs.operators;
let field = 0;
const formSubject = new Subject();
const closeSubject = new Subject();
const formObservable = formSubject.asObservable();
const closeObservable = closeSubject.asObservable();
document.getElementById('change').onclick = () => {
console.clear();
formSubject.next({ field: ++field });
};
document.getElementById('close').onclick = () => {
console.clear();
closeSubject.next(true);
};
formObservable.pipe(
skip(1),
distinctUntilChanged(),
switchMap((form) => race(
of(form).pipe(delay(2000)),
closeObservable.pipe(take(1)).pipe(switchMap(() => of(form)))
))
).subscribe(res => {
console.log(res);
});
formSubject.next({ field });
<div>
<button id="change" onclick="change()">CHANGE</button>
<button id="close" onclick="close()">CLOSE</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.2/rxjs.umd.js"></script>
Upvotes: 2
Reputation: 2618
You want to use race
. for example race(observableOne$, observableTwo$)
will only emit the value of the first Observable to emit a value.
https://www.learnrxjs.io/operators/combination/race.html
Upvotes: 0