I am using a Snackbar to display error and warning messages to the user. Sometimes these can happen close to each other in time, closer than the display duration time of the first message. So close that it does not give enough time to the user to read the first message before overwriting with the second message.
Is there a way of changing the behaviour to waiting for the end of the first message before displaying the second, or piling them up?
Instead of invoking the Snackbar for each message, you could put all of them into an array to mimic a 'queue' of messages. I would suggest having a service which is responsible for handling this.
Then, in this service you can subscribe to the Snackbar's afterDismissed()
callback which will fire whenever the Snackbar closes. Here's a simple example of what that would look like:
messageQueue: string[] = [
'Message 1',
'Message 2',
'Message 3'
]
private displaySnackbar(): void {
const nextMessage = this.getNextMessage();
if(!nextMessage){
return;
}
this.snackBar.open(nextMessage, undefined, { duration: 1000 })
.afterDismissed()
.subscribe(() => {
this.displaySnackbar();
});
}
private getNextMessage(): string | undefined {
return this.messageQueue.length ? this.messageQueue.shift() : undefined;
}
EDIT:
So as to avoid any confusion, in the example I have provided I do not recommend calling displaySnackbar()
directly (hence the private
visibility scope). Instead, here's how I have exposed it (as you can see in the Stackblitz demo from below):
addMessage(message: string): void {
this.messageQueue.push(message);
if(!this.processingMessage) {
this.displaySnackbar();
}
}
This just depends on the processingMessage
flag to determine whether or not it should invoke the displaySnackbar()
method. Of course we will also need to set this flag so here's the updated displaySnackbar()
:
private displaySnackbar(): void {
const nextMessage = this.getNextMessage();
if(!nextMessage){
this.processingMessage = false; // No message in the queue, set flag false
return;
}
this.processingMessage = true; // A message was dequeued and is being processed
this.snackBar.open(nextMessage, undefined, { duration: 1000 })
.afterDismissed()
.subscribe(() => {
this.displaySnackbar();
});
}
Here is the basic, working Stackblitz demo.
In the demo, you will see that you can 'spam click' the 'Add Message' button which will queue up all of the messages that get created, but the Snackbar will only display them once each message has finished being displayed for 1 second.