18

How to display the Angular 2 Material Progress Spinner as a somewhat transparent overlay of the current view (a page or a modal dialog)?

FAISAL
  • 33,618
  • 10
  • 97
  • 105
Nicole Naumann
  • 1,018
  • 2
  • 10
  • 23

4 Answers4

40

I was inspired by: Overriding Angular Material Size and Styling of md-dialog-container

I solved it like this:

Create a New Component

Create a new component ProgressSpinnerDialogComponent

The content of progress-spinner-dialog.component.html:

<mat-spinner></mat-spinner>

The content of progress-spinner-dialog.component.ts:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-progress-spinner-dialog',
  templateUrl: './progress-spinner-dialog.component.html',
  styleUrls: ['./progress-spinner-dialog.component.css']
})
export class ProgressSpinnerDialogComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

Add a Style

In styles.css add:

.transparent .mat-dialog-container {
    box-shadow: none;
    background: rgba(0, 0, 0, 0.0);
}

Use the Component

Here an example usage of the progress spinner:

import { Component, OnInit } from '@angular/core';
import { MatDialog, MatDialogRef } from "@angular/material/dialog";
import { Observable } from "rxjs";
import { ProgressSpinnerDialogComponent } from "/path/to/progress-spinner-dialog.component";

@Component({
  selector: 'app-use-progress-spinner-component',
  templateUrl: './use-progress-spinner-component.html',
  styleUrls: ['./use-progress-spinner-component.css']
})
export class UseProgressSpinnerComponent implements OnInit {

  constructor(
    private dialog: MatDialog
  ) {
    let observable = new Observable(this.myObservable);
    this.showProgressSpinnerUntilExecuted(observable);
  }

  ngOnInit() {
  }

  myObservable(observer) {
    setTimeout(() => {
      observer.next("done waiting for 5 sec");
      observer.complete();
    }, 5000);
  }

  showProgressSpinnerUntilExecuted(observable: Observable<Object>) {
    let dialogRef: MatDialogRef<ProgressSpinnerDialogComponent> = this.dialog.open(ProgressSpinnerDialogComponent, {
      panelClass: 'transparent',
      disableClose: true
    });
    let subscription = observable.subscribe(
      (response: any) => {
        subscription.unsubscribe();
        //handle response
        console.log(response);
        dialogRef.close();
      },
      (error) => {
        subscription.unsubscribe();
        //handle error
        dialogRef.close();
      }
    );
  }
}

Add it to the app.module

 declarations: [...,ProgressSpinnerDialogComponent,...],
 entryComponents: [ProgressSpinnerDialogComponent],
Tomek
  • 3,267
  • 2
  • 22
  • 23
toongeorges
  • 1,844
  • 17
  • 14
  • 3
    best answer right here. You may also want to add the option, "disableClose: true", so that the user can't exit out of it on their own – Sharpiro May 18 '18 at 16:31
  • @Sharpiro yes, you are right, I will update the answer – toongeorges May 24 '18 at 15:11
  • Very good solution, thx! @toongeorges by the variation with spinner I would add the 'disableClose: true' option too. – Mark Aug 16 '18 at 08:29
  • `myObservable = (observer) => {` if using `this.` within **http** **get** / **post** within the observable – novice in DotNet May 30 '22 at 12:51
  • Dialog get transparent color. but still When Dialog full loaded I get the white background, and also the component which is called from dialog, have transparet background color. Angular 16 – ImIGI Jun 06 '23 at 21:37
7

Use the below code to achieve the opaque:

HTML

<div style="height: 800px" [class.hide]="show">
   <button class="btn btn-success" (click)="showSpinner()">Show spinner</button>
</div>
<app-spinner [show]="show" [size]="150"></app-spinner>

COMPONENT

import { Component, Input } from '@angular/core';

@Component({
    selector: 'app-spinner',
    template: `
      <i aria-hidden="true" class="fa fa-spinner fa-spin" [style.font-size.px]="size" *ngIf="show"></i>
    `
})
export class SpinnerComponent {
  @Input() size = 50;
  @Input() show = false;
  
  showSpinner() {
    this.show = true;
  }
}

CSS

.hide {
  opacity: 0;
}

LIVE DEMO

developer033
  • 24,267
  • 8
  • 82
  • 108
Aravind
  • 40,391
  • 16
  • 91
  • 110
3

Based on A bit different approach: Two components, first to open the dialog, second is the dialog. In the component you want to show the spinner just add:

<app-dialog-spinner *ngIf="progressSpinner"></app-dialog-spinner>

And control the *ngIf in your logic. Above is all you need to call the spinner so the component stays nice and clean.

Dialog spinner component:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material';

// Requires a transparent css (panel)id in a parent stylesheet e.g.:
// #DialogSpinnerComponent {
//   box-shadow: none !important;
//   background: transparent !important;
// }

@Component({
  selector: 'app-do-not-use',
  template: `<mat-spinner></mat-spinner>`,
  styles: []
})
export class DialogSpinnerDialogComponent { }

@Component({
  selector: 'app-dialog-spinner',
  template: ``,
  styles: []
})
export class DialogSpinnerComponent implements OnInit, OnDestroy {

  private dialog: MatDialogRef<DialogSpinnerDialogComponent>;

  constructor(
    private matDialog: MatDialog,
  ) { }

  ngOnInit() {
    setTimeout(() => {
      this.dialog = this.matDialog.open(DialogSpinnerDialogComponent, { id: 'DialogSpinnerComponent', disableClose: true });
    });
  }
  ngOnDestroy() {
    setTimeout(() => {
      this.dialog.close();
    });
  }

}

Declare the components in your module and of course register DialogSpinnerDialogComponent in your entryComponents. Add the css properties to a parent stylesheet. This can probably be improved but I'm a bit pressed for time.

PVermeer
  • 2,631
  • 2
  • 10
  • 18
1

I was able to get this to work with Angular 13 following Tomek's solution however I had to add: encapsulation: ViewEncapsulation.None to my @Component declaration that is being used as a dialog:

import { Component, OnInit, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-progress-spinner-dialog',
  templateUrl: './progress-spinner-dialog.component.html',
  styleUrls: ['./progress-spinner-dialog.component.css'],
  // this needed to override the mat-dialog-container CSS class
  encapsulation: ViewEncapsulation.None
})

Without this reference to ViewEncapsulation.None I was not able to get the CSS override to work. I found this great hint here: Learn Angular 11 MatDialog Basics

J.Gentsch
  • 19
  • 2