I need to create a toaster.
I have the Subject
this.toast$ = this.toastSubject.asObservable().pipe(
filter(toast => toast !== null),
concatMap((toast) => of(toast).pipe(delayWhen(() => timer(5000)), skip(1), startWith(toast)))
);
The show toaster method
show(type: ToastType, title: string, body: string, delay?: number): void {
this.toastSubject.next({ type, title, body, delay: delay || undefined, showIcon: true });
}
I'm subscribing inside the component and pushing inside the array the toaster notifications. So by using concatMap and delay it waits for the observable to finish and then emits another one that lasts 5 seconds.
My issue:
If i close the notification after 1 second, and the delay is 5 seconds, i still have to wait 4 seconds for the 2nd notification.
I've made another observable to listen to the closing event of the notification but how can i stop the delay and emit the next value immediately??
I've tried with takeUntil.
I've even tried a custom delayUntil
export function delayUntil<T>(
notifier: Observable<SafeAny>
): OperatorFunction<T, T> {
return (source) =>
source.pipe(
publish((published) => {
const delayed = new Observable<T>((subscriber) => {
let buffering = true;
const buffer: T[] = [];
const subscription = new Subscription();
subscription.add(
notifier.subscribe(
() => {
buffer.forEach((value) => subscriber.next(value));
subscriber.complete();
},
(error) => subscriber.error(error),
() => {
buffering = false;
buffer.length = 0;
}
)
);
subscription.add(() => {
buffer.length = 0;
});
subscription.add(
published.subscribe(
(value) => buffering && buffer.push(value),
(error) => subscriber.error(error)
)
);
return subscription;
});
return concat(delayed, published);
})
);
}
It still doens't work.
Thank you !
CodePudding user response:
race
is probably what you are looking for !
this.toast$ = this.toastSubject.pipe(
concatMap((toast) =>
of(toast).pipe(
delayWhen(() => race([this.toastClose$, timer(5000)])),
skip(1),
startWith(toast)
)
)
);