Issue
I have implemented a “snackbar service” that display a snackbar:
snackbar.service.ts
import { Subscription } from 'rxjs/Subscription';
import { Subject } from 'rxjs/Subject';
import { Inject, Injectable, OnDestroy } from '@angular/core';
import { MatSnackBar, MdSnackBarConfig } from '@angular/material/snack-bar';
import { MdSnackBarRef, SimpleSnackBar } from '@angular/material/snack-bar';
export class SnackBarMessage {
message: string;
action: string = null;
config: MdSnackBarConfig = null;
}
@Injectable()
export class SnackBarService implements OnDestroy
{
private messageQueue: Subject<SnackBarMessage> = new Subject<SnackBarMessage>();
private subscription: Subscription;
private snackBarRef: MdSnackBarRef<SimpleSnackBar>;
constructor(public snackBar: MatSnackBar){
this.subscription = this.messageQueue.subscribe(message => {
this.snackBarRef = this.snackBar.open(message.message, message.action, message.config);
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
/**
* Add a message
* @param message The message to show in the snackbar.
* @param action The label for the snackbar action.
* @param config Additional configuration options for the snackbar.
*/
add(message: string, action?: string, config?: MdSnackBarConfig): void{
if ( !config ){
config = new MdSnackBarConfig();
config.duration = 10000;
}
let sbMessage = new SnackBarMessage();
sbMessage.message = message;
sbMessage.action = action;
sbMessage.config = config;
this.messageQueue.next(sbMessage);
}
}
I want display multiple snackbars in sequence:
test.component.ts
import { Component } from '@angular/core';
import { SnackBarService } from 'app/core/services/snackbar.service';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent {
constructor(public snackBarService: SnackBarService) {
this.snackBarService.add('A');
this.snackBarService.add('B');
this.snackBarService.add('C');
}
}
But all message are displayed at same time (overlapping).
How can I wait for a snackBar afterDismissed for display a new message into messageQueue?
Solution
As @Aamir Khan pointed out – using afterDismissed
, I have tweaked your code a bit.
showNext() {
if (this.msgQueue === 0) {
return;
}
let message = this.msgQueue.shift();
this.isInstanceVisible = true;
this.snackBarRef = this.snackBar.open(message.message, message.action, {duration: 2000});
this.snackBarRef.afterDismissed().subscribe(() => {
this.isInstanceVisible = false;
this.showNext();
});
}
And inside add()
added this –
this.msgQueue.push(sbMessage);
if (!this.isInstanceVisible) {
this.showNext();
}
Caution – Its kind of a dirty and non standard way, not an ideal user experience (IMO), above code might have some memory leaks and race conditions, due to usage of flags.