Adding an Icon to the Angular Material Snackbar in Angular 5: A Step-by-Step Guide

I recently started using Angular and have incorporated Angular Material Design for my UI elements.

Within my application, I am utilizing a snackbar component.

However, I am facing difficulty in adding an icon inside the snackbar despite trying various solutions from Stackoverflow threads.

Here is the code snippet:

this.snackBar.open('You are already registered. Please log in.', '', { duration: 2000 });

https://i.stack.imgur.com/lkrvN.png

I aim to include the icon as shown in the image, but currently, my snackbar does not have this icon. Any guidance on how to achieve this would be greatly appreciated.

https://i.stack.imgur.com/QPQiL.png

If anyone could assist me in implementing this feature, it would be highly beneficial.

Answer №1

Here is my approach

  1. Start by creating a component
  2. Next, develop a Service specifically for handling snack bars
  3. Add the component to a module by importing it in both declarations and entryComponents
  4. Now you can effectively utilize the service

For demonstration purposes, consider the following example:

my-snackbar.component.ts

 import { Component, OnInit, Inject } from '@angular/core';
 import { MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar';

    @Component({
      selector: 'my-snackbar',
      templateUrl: './snackbar.component.html',
      styleUrls: ['./snackbar.component.scss']
    })
    export class MySnackbarComponent implements OnInit {
      constructor(@Inject(MAT_SNACK_BAR_DATA) public data: any) {
        console.log(data); 
      }

      ngOnInit() {}

      get getIcon() {
        switch (this.data.snackType) {
          case 'Success':
            return 'done';
          case 'Error':
            return 'error';
          case 'Warn':
            return 'warning';
          case 'Info':
            return 'info';
        }
      }
    }

.........

my-snackbar.component.html

<div fxLayout="row" class="snack-container">
  <div>
    <mat-icon>{{getIcon}}</mat-icon>
  </div>
  <div>
    <span>{{data.message}}</span>
  </div>
</div>

.........

my-snack-bar.service.ts

import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MySnackbarComponent } from '../components/snackbar/my-snackbar.component';

@Injectable({
  providedIn: 'root'
})
export class MySnackBarService {
  constructor(private snackBar: MatSnackBar) {}
  public openSnackBar(message: string, action: string, snackType?: snackType) {
    const _snackType: snackType =
      snackType !== undefined ? snackType : 'Success';

    this.snackBar.openFromComponent(SnackbarComponent, {
      duration: 2000,
      horizontalPosition: 'end',
      verticalPosition: 'top',
      data: { message: message, snackType: _snackType }
    });
  }
}

........

app.module.ts

@NgModule({
  declarations: [
    SnackbarComponent
  ],
  imports: [
...
  ],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents: [
    SnackbarComponent
  ]
})
export class AppModule {}

.......

other.component.ts

import { Component, OnInit } from '@angular/core';
import { MySnackBarService } from '../../services/my-snack-bar.service';

@Component({
...
})
export class SomeComponent implements OnInit {

  constructor(
    private snack: MySnackService
  ) {}

  ngOnInit() {
  }


  openSnack() {
    this.snack.openSnackBar('Testing snack', '', 'Success');
  }
}

Answer №2

Consider utilizing openFromComponent or openFromTemplate functions within the MatSnackBar Service instead of using the basic open method.

Answer №3

Check out this additional code snippet by Sivuyile TG Magutywa to enhance your project:

HTML for the Snackbar component:

<div class="snack-container box-{{getIcon.type}}">
  <div class="snack-container-message">
    <div>
      <i class="fas {{getIcon.icon}}"></i>
    </div>
    <div>
      <span>{{data.message}}</span>
    </div>
  </div>
  <div class="snack-container-icon">
    <i class="fas close" (click)="closeSnackbar()"></i>
  </div>
</div>

TypeScript file for the Snackbar component:

export class SnackbarComponent implements OnInit {

  constructor(@Inject(MAT_SNACK_BAR_DATA) public data: any) {
    console.log(data);
  }

  ngOnInit() {}

  get getIcon() {
    switch (this.data.snackType) {
      case 'success':
        return {type: this.data.snackType, icon: 'check'};
      case 'error':
        return {type: this.data.snackType, icon: 'faults'};
      case 'warn':
        return {type: this.data.snackType, icon: 'warning_outline'};
      case 'info':
        return {type: this.data.snackType, icon: 'info'};
    }
  }

  closeSnackbar() {
    this.data.snackBar.dismiss();
  }

}

Snackbar service code:

export class SnackBarService {
  messageText: string [];
  constructor(
    public snackBar: MatSnackBar,
  ) {
  }
public openSnackBar(message, type, duration?, verticalPosition?, horizontalPosition?) {
    const _snackType = type !== undefined ? type : 'success';
    this.snackBar.openFromComponent(SnackbarComponent, {
      duration: duration || 4000,
      horizontalPosition: horizontalPosition || 'end',
      verticalPosition: verticalPosition || 'top',
      data: { message: message, snackType: _snackType, snackBar: this.snackBar }
    });
  }

}

How to use the Snackbar in another component:

constructor(private snackBar: SnackBarService) {}
testSanck() {
   this.snackBar.openSnackBar('User Not Found', 'error');
}

Answer №4

When using the open method of the MatSnackBar, it is limited to only opening simple snack bars with text. For more advanced snack bars, like ones with icons included, a separate component must be created and then opened using the openFromComponent method.

Answer №5

If you're still on the hunt for a solution, there's a simpler method that doesn't require creating new components or changing how you call your snackbar.

All you need to do is add a class to the material snackbar like so:

this.snackBar.open(message, "Dismiss", {
    panelClass:'error-alert-snackbar'
});

Then in your CSS, define your class and customize it with colors:

.error-alert-snackbar{
    color: white!important;
    background-color:red !important;
   .mat-simple-snackbar-action {
       color:white !important;
   }
}

Furthermore, you can incorporate an icon into your class using "yourclass:after":

.error-alert-snackbar:after{      
    font-family: "FontAwesome";
    content: "\f071";
}

In the snippet above, the "content" refers to the Unicode version of the Font Awesome icon name. You can find this information on the icon's Font Awesome page under the icon image. For instance, the code for fa-exclamation-triangle would be displayed as follows:

<i class="fa fa-exclamation-triangle"></i>

If you don't have access to the material snackbar HTML, you can directly add the icon to your CSS class and apply it to the snackbar upon opening.

NOTE: It's unclear whether this feature was available when this question was initially posed or if it was introduced after Angular 5.

Answer №6

Service.ts

import {MatSnackBar,MatSnackBarConfig,MatDialog} from '@angular/material';

showNotification(message: string, type: string, duration?: number) {
const config = new MatSnackBarConfig();
config.duration = 5000;
if (duration) {
    config.duration = duration;
}
config.politeness = 'assertive';
if (type === 'Error') {
    config.panelClass = ['without-image'];
} else if(type==='Warn'){
    config.panelClass = ['with-image'];
}
this.snackBar.open(message, 'x', config);
}

style.css

.without-image{
    background: red;
    text-align: center !important;
}
.with-image{
    background: red;
    text-align: center !important;
    position: relative;
    padding-left: 45px !important;
}
.with-image::before{
    content: '';
    position: absolute;
    top: 13px;
    left: 15px;
    width: 20px;
    height: 20px;
    background-image: url('images/warning.png');
    background-position: center;
    background-size: contain;
    background-repeat: no-repeat;
}

component.ts

import { ApiService } from 'src/app/services/api.service';

constructor(private service: ApiService) {}

this.service.showNotification('You are already registered.Please log in.', 'Warn');

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Shifting attention to an angular 6 form field

I am developing an application in Angular which involves creating, reading, updating, and deleting user information. I have a requirement for the username to be unique and need to display an error message if it is not unique, while also focusing on the use ...

Creating validation for an autosave reactive form in Angular 2: A step-by-step guide

Seeking advice on implementing an autosave feature for a reactive Angular 2 form. The idea is that as the user types in values, the form should automatically save if the input is valid. Below is the code snippet: export class BusinessFoundationsPage { ...

modify pseudo element's style in Angular based on a particular condition

I am trying to change the style of :before based on a condition. I attempted to implement the solution provided at , but it did not work as expected. Here is my code: .sender:before { content: ""; width: 0px; ...

The Vercel error indicates that the file or directory '/var/task/node_modules/shiki/themes/one-dark-pro.json' does not exist

import { serialize } from 'next-mdx-remote/serialize'; import readingTime from 'reading-time'; import remarkGfm from 'remark-gfm'; import rehypeSlug from 'rehype-slug'; import rehypeAutolinkHeadings from 'rehype ...

Filter the angular accordion by passing a simple array value into the input

I am looking to filter my array of accordion items based on the value of the question matching the input I provide. I have tried using the filter method for this. this.accordionItems = [ { "topic":"polizze", " ...

What is the best way to get both the id and name of a selected item in Angular?

Within my select field, data is dynamically populated based on names. My objective is to not only capture the selected name but also its corresponding ID. Here's a snippet of my HTML template: <select class="custom-select d-block w-100" id="test" ...

The Clarity Design side menu becomes unscrollable when the content is too long for the view

Currently, I am facing an issue with the sidenav where the navigation links go beyond the view and I am unable to scroll to see the "hidden" links unless I zoom out. My frontend framework is Angular 5 and this is how I organized the components: <nav c ...

My app's custom barrel configurations don't appear to be functioning properly in Angular 2's system-config.ts

My system-config.ts file is as follows: 'use strict'; // SystemJS configuration file, for more information visit: // https://github.com/systemjs/systemjs // https://github.com/systemjs/systemjs/blob/master/docs/config-api.md /***************** ...

Ensuring File Size and Format Compliance in Angular's HTML and TypeScript

I'm currently tackling a file upload feature on an ASP.net webpage using Angular. I have a question: How can I verify if the uploaded file is either a PDF or JPG and does not exceed 2MB in size? If these conditions are not met, I would like to displa ...

A guide on converting your current Angular app into a "fully strict" application – follow these steps!

I started developing an Angular Application back in Angular 4 and now it has been upgraded to Angular 12. However, during the initial development phase, the strict mode was not enabled. Now that the application is stable and live in production, I am lookin ...

I found that the Angular checkbox was only allowing me to select one value at a time instead of

Hey there, I am currently working on an angular tickbox where I want to be able to tick multiple values. However, I am facing an issue where only the latest checkbox value is displayed instead of both English and German together. How can I populate data fr ...

Is there a way to load an image onto the ngx-image-cropper without triggering the imageChangedEvent event?

My latest project involved creating a custom cropper using ngx-image-cropper, which allows for cropping and rotating images. For the sprint demo, I needed the images to be displayed as soon as the application loads without having to trigger the fileChangeE ...

The module 'DynamicTestModule' has imported an unexpected directive called 'InformationComponent'. To resolve this issue, please include a @NgModule annotation

Even though I found a similar solution on Stackoverflow, it didn't resolve my issue. So, let me explain my scenario. When running the ng test command, I encountered the following error: Failed: Unexpected directive 'InformationComponent' i ...

How can I receive live notifications for a document as soon as it is created?

My Angular app is connected to Cloud Firestore, and I've created a function in a service to retrieve a user's rating from the 'ratings' collection. Each rating is stored in this collection with the document ID being a combination of the ...

Angular, manipulating components through class references instead of creating or destroying them

I am exploring ways to move an angular component, and I understand that it can be achieved through construction and destruction. For example, you can refer to this link: https://stackblitz.com/edit/angular-t3rxb3?file=src%2Fapp%2Fapp.component.html Howeve ...

RouterLink causing component not to reload

In my welcome.component, I have a menu and tab. When I click on a menu item, the routerlink doesn't initiate a new request, causing the tab component not to reload. The tab component is called by multiple router links and should be reloaded every time ...

Vercel - Deploying without the need to promote the project

How can I deploy my Nextjs app to production in a way that allows me to run E2E tests on a "pre-prod" version before promoting it to prod, similar to using a preview URL without public traffic being directed there? I am looking for a process where I can v ...

Implementing type inference for response.locals in Express with TypeScript

I need to define types for my response.locals in order to add data to the request-response cycle. This is what I attempted: // ./types/express/index.d.ts declare global { declare namespace Express { interface Response { locals: { ...

Deploying an Angular application on Firebase is a great way to

I am facing an issue with hosting my Angular(5) project on Firebase. Although I have successfully deployed the application, when I access the project URL, it displays a default Firebase hosting screen instead of my actual Angular project. https://i.stack. ...

I'm trying to figure out the best way to successfully pass a prop to another component in TypeScript without running into the frustrating issue of not being able to

I have been facing an issue while trying to pass a prop from a custom object I have defined. The structure of the object is as follows: export type CustomObjectType = { data?: DataObject }; export type DataObject = { id: number; name: stri ...