Job
Job

Reputation: 485

How to dismiss/close an Angular Snackbar element from inside element

I currently have a snackbar element with a mat-progress-bar inside it. I'd like to close the snackbar element. My code currently looks like this.

import { MAT_SNACK_BAR_DATA, MatSnackBar } from '@angular/material';
import { map } from 'rxjs/operators';

 @Component({
  selector: 'app-upload-progress-snackbar',
  template: `
  Progress:
  <mat-progress-bar mode="determinate" [value]="progress | async" *ngIf="progress !== undefined"></mat-progress-bar>`,
  styles: [`mat-progress-bar { margin-top: 5px;}`],
})
export class UploadProgressComponent {
  constructor(@Inject(MAT_SNACK_BAR_DATA) public data) { }

  private started = false;
  public progress = this.data.uploadProgress.pipe(
    map(({ loaded, total }) => {
      if (loaded === undefined) {
        return !this.started ? 0 : 100;
      } else {
        this.started = true;
        return Math.round(loaded / (total || loaded) * 100);
      }
    },
  ));
}

Upvotes: 11

Views: 35805

Answers (5)

beanic
beanic

Reputation: 562

Maybe this article could help https://hoshcoding.com/courses/1/angular-material-snackbar.

Here you can see a complete example with angular material snackbar and how undo an action.

If you need the code here is the example:

openSnackbar(message, action) {
    let snackBarRef = this.snackBar.open(message, action);
    snackBarRef.afterDismissed().subscribe(() => {
      console.log("The snackbar is dismissed");
    });
    snackBarRef.onAction().subscribe(() => {
      console.log("The snackbar action was triggered!");
    })
  }

Regards

Upvotes: 0

Kuppusamy
Kuppusamy

Reputation: 451

Check out this Awesome Demo on Stackblitz.

export class PizzaPartyComponent {
  constructor(public snackBarRef: MatSnackBarRef<PizzaPartyComponent>,
  @Inject(MAT_SNACK_BAR_DATA) public data: any){}
}

Use snackBarRef.dismiss() to close it.

If you face any flickering on showing snack bar, run it inside the Ngzone.

constructor(private _snackBar: MatSnackBar, private zone: NgZone) {}

openSnackBar() {
  this.zone.run(()=>{
    this._snackBar.openFromComponent(PizzaPartyComponent, {
      data: this.message,
      duration: this.durationInSeconds * 1000,
    });  
  });
}

Upvotes: 3

Christopher Grigg
Christopher Grigg

Reputation: 2308

A good way to do this is leveraging Dependency Injection inside the custom Snack Bar component to create a snack bar reference. Then close the component using this reference.

CustomSnackBar.ts

constructor(
    private snackBarRef: MatSnackBarRef<GeneralSnackbarComponent>,
    @Inject(MAT_SNACK_BAR_DATA) public data: any
) { }

public dismiss(): void {
    this.snackBarRef.dismiss();
    event.preventDefault();
}

CustomSnackBar.html

<button id="cancelBtn" mat-button (click)="dismiss()">
    Cancel
</button>

Upvotes: 6

Sandeep Gupta
Sandeep Gupta

Reputation: 7250

Marshal's solution is nice but requires a lot of effort.

The following solution is cleaner (No need to pass snack bar reference or listen to any dom event)

Stackblitz

Snackbar component:

@Component({
  selector: 'app-upload-progress-snackbar',
  template: `
  Hello :)
  <button mat-button color="primary" (click)="dismiss()">Dismiss</button>  
  `,

})
export class UploadProgressComponent {
  constructor(
    @Inject(MAT_SNACK_BAR_DATA) public data) {}

  dismiss(){
    this.data.preClose(); //access preClose function when you want to close snackbar
  }
}

Snackbar opener code:

openSnackBar() {
    const snackBar = this.snackBar.openFromComponent(UploadProgressComponent, {
      data: {preClose: () => {snackBar.dismiss()} } //pass a function to be called when you want to close the snackbar
    });
  }

Upvotes: 13

Marshal
Marshal

Reputation: 11081

You can do the following to achieve this.

This snack-bar is like a mat-dialog.. you have to call the dismiss() on a MatSnackBarRef

DI renderer and MatSnackBarRef... you don't need renderer if you are going to dismiss some other way, this is just for demonstration purposes.

 @Inject(MAT_SNACK_BAR_DATA) public data,
    private _snackRef: MatSnackBarRef<UploadProgressComponent>,
    private ren:Renderer2

If you wanted to dismiss on progress bar completing you could call dismiss() in that logic. I am going to dismiss on click.

Create click event listener in your constructor...

{ 
  setTimeout(()=>{
    let snackEl = document.getElementsByClassName('mat-snack-bar-container').item(0);
    ren.listen(snackEl, 'click', ()=>this.dismiss())
  })

create your dismiss()

  dismiss(){
    this._snackRef.dismiss();
  }

Stackblitz

https://stackblitz.com/edit/angular-mdyher?embed=1&file=app/snack-bar-component-example.ts

Upvotes: 18

Related Questions