11

I am new to angular and I am using Angular Material Design for UI.

In my application I have a snackbar .

Now I want to set an Icon inside the snackbar but I tried some Stackoverflow post I can't set it .

code:

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

enter image description here

I want to set the icon as in the image but I have the below snackbar without icon .I don't know how to add this .

enter image description here

can anyone help me to add this.

Zhu
  • 3,679
  • 14
  • 45
  • 76

6 Answers6

24

This how I did it

  1. Create a component
  2. Create a Service for the snackBar
  3. add the component to a module. import it in declarations and entryComponents
  4. Use the service

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');
  }
}
Sivuyile TG Magutywa
  • 1,041
  • 12
  • 15
  • This is great. Ended up using this for an app I've been working on. Also like how all the options are nested in the service. Thanks for posting this. – Josh Aug 08 '19 at 15:58
7

Try openFromComponent or openFromTemplate methods of the MatSnackBar Service instead of plain open.

PeS
  • 3,757
  • 3
  • 40
  • 51
3

some extra code in Sivuyile TG Magutywa make it complete:

in Snackbar HTML:

<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>

in SnackBar TS file:

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();
  }

}

in snackbar service:

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 }
    });
  }

}

usage in other component:

constructor(private snackBar: SnackBarService) {}
testSanck() {
   this.snackBar.openSnackBar('User Not Found', 'error');
}
Me Sa
  • 1,036
  • 12
  • 14
2

The open method of the MatSnackBar lets you only open snack bars with text, that is to say simple snack bars. If you want to have a more sophisticated snack bar - such as one with an icon added -, you will have to create a distinct component and open that very component with the openFromComponent method.

van_Skyr
  • 613
  • 2
  • 5
  • 8
1

For anyone else still looking for this answer, there is a much easier way to do this without creating new components or changing how you call your snackbar.

You can add a class to the material snackbar like this:

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

Then in your css, add your class. You might add some colors like this:

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

Next you can use "yourclass:after" to add an icon to that class:

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

Where the "content" above is the Unicode version of the font awesome icon name you would normally call. You can always find it on the icon's Font Awesome page under the picture of the icon where if shows you how to call it. In this case its fa-exclamation-triangle. You would normally call it like this

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

But since you dont have access to the material snackbar html you can add the icon directly to your css class as i have shown and then attach that css class to the snackbar on open as shown

EDIT: I don't know if this is new functionality for the snackbar created after Angular 5 or if it existed at the time of this question.

Matt Ke
  • 3,599
  • 12
  • 30
  • 49
Brett T
  • 25
  • 6
0

Service.ts

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

openSnackBar(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.openSnackBar('You are already registered.Please log in.', 'Warn');
frank
  • 1,217
  • 2
  • 10
  • 18
Sherin
  • 11
  • 1
  • Please elaborate your answer a little. What does it do? Why? How does it differ from the other answers? – ahuemmer Apr 02 '22 at 06:35