Create an Angular Snackbar Service

While working on my reporting app, I came across the need to display various on screen messages, whenever the user needs additional information. This could be related to form errors, backend error responses or just informal messages based on any particular user action.

Since I already have Angular Material available as a dependency, I was happy to see it provides a very helpful snack-bar component out of the box.

In the following few steps, we will create an Angular service for displaying a snack-bar. Since you can just instantiate this service in your constructor, on any component you would require, it's like having an app wide messenger service.

Why do this as a service?

If you are only ever going to use the snack-bar at one place in your entire app, this might not be greatly beneficial, though you should always try to separate your concerns. By creating a service, we can configure the implementation of the snackbar away from the rest of our components and have any and all functionality related to the snack-bar in its own class.

Getting started

We start by creating a new service. I'll do it manually here but you could also create it with the Angular CLI by calling "ng generate service snackbar" or "ng g s snackbar" from your command line.

Create a file called "snackbar.service.ts" and import the required packages:

// snackbar.service.ts
import { Injectable } from '@angular/core';
import {
  MatSnackBar,
} from '@angular/material/snack-bar';

@Injectable({
  providedIn: 'root',
})
export class SnackBarService {}

Now that we have our service available, we create an instance of the snack-bar in our constructor:

// snackbar.service.ts
export class SnackBarService {

  // Add constructor
  constructor(private matSnackBar: MatSnackBar) {}
}

From here, we can define a method for calling it with our service:

// Added method to class
  showSnackBar(message: string) {
    this.matSnackBar.open(message);
  }

This is pretty much it. If you now want to use this snackbar, create the above service in your components constructor and call the "showSnackBar" method at any point you need it, passing the desired message.

Extending the default configuration

The above example gets the job done but we can define other properties to configure the snackbar to our liking. Have a look at the entire service code that I currently use in my app:

@Injectable({
  providedIn: 'root',
})
export class SnackBarService {
  private duration: number = 5000;
  private verticalPosition: MatSnackBarVerticalPosition = 'top';
  private horizontalPos: MatSnackBarHorizontalPosition = 'right';
  private action: string = 'OK';

  constructor(private matSnackBar: MatSnackBar) {}

  showSnackBar(message: string, style?: string) {
    this.matSnackBar.open(message, this.action, {
      duration: this.duration,
      verticalPosition: this.verticalPosition,
      horizontalPosition: this.horizontalPos,
      panelClass: style,
    });
  }
}

The first parameter of the snack-bar "open" method is the message to be displayed. The second is a string for the dismiss action. Here, the user can dismiss the snack-bar on screen by clicking the button.

The third parameter takes in an object. In the above example, I customize the duration of the time the snack-bar is visible, before automatically disappearing from the screen.

The next two properties define the position, the snack-bar should appear at. If you wanted to customize this for different components, you can add that property to your service method and simply pass the desired option.

The "panelClass" lets you assign a style class to the snack-bar. You could define a CSS class in your stylesheet and change, for example, the font-weight or color of your snack-bar.

Example:

//styles.scss
.error-snackbar {
  color: red;
  font-weight: bold;
}

In the component, you can then call the snack-bar method with the CSS class:

this.snackBar.showSnackBar(errMsg, 'error-snackbar');

I hope you found this little tutorial to be helpful. As always, let me know what you think or if you found any errors in my examples.

Take care,

Florian