blubberbo
blubberbo

Reputation: 4613

Angular 2+ (8) Material Snack Bar Displays but is not Dismissing

I have been pulling my hair out trying to fix this and for the life of me cannot figure it out. I have an application with "@angular/core": "~8.2.14" and "@angular/material": "^8.2.3", and I have a Snack Bar that I use a global service to call. The dismiss button used to work just fine (around a year ago) but now for some reason has stopped working. This is the code I have:

notification-snack-bar.component.ts

export class NotificationSnackBarComponent {
  constructor(
    @Inject(MAT_SNACK_BAR_DATA) public data: any,
    public snackBar: MatSnackBar,
    private notificationService: NotificationService = new NotificationService(),
  ) {
    // message logic here - removed for brevity
  }
  // set the default values
  message = 'Unknown error...';
  action = 'dismiss';

  // close the snack bar
  dismiss(): void {
    // indicate on the service that the error is being closed
    this.notificationService.errorBeingDisplayed = false;
    // dismiss the actual snack bar
    this.snackBar._openedSnackBarRef.dismiss();
  }
}

notification-snack-bar.component.html

<div class="notification-snack-bar-container flex">
  <div>
    <span class="mat-warn-color"
      >An Error Occurred: {{ message }}<br /><span *ngIf="timerCount > 0"
        >Timer: {{ timerCount }}</span
      ></span
    ><br /><span>See the console for the full error.</span>
  </div>
  <button mat-button color="accent" (click)="dismiss()">{{ action }}</button>
</div>

notification.service.ts

export class NotificationService {
  constructor() {}
  // a local flag to keep track of whether or not an error is being shown
  public errorBeingDisplayed = false;
  // the subject to display the error
  private displayErrorSource = new Subject<string>();
  // the observable used to display the error
  public displayError$ = this.displayErrorSource.asObservable();

  /**
   * display any error message that is caught on the page
   *  @params error: string
   */
  //
  displayCaughtError(error: string) {
    // only if there is no error being displayed currently
    if (!this.errorBeingDisplayed) {
      console.log(error);

      // indicate an error is being displayed
      this.errorBeingDisplayed = true;
      // call the .next() method on the source to push the next error to the snack bar
      this.displayErrorSource.next(error);
    }
  }
}

lol-pickem-error.handler.ts

export class LolPickemErrorHandler implements ErrorHandler {
  constructor(
    private notificationService: NotificationService = new NotificationService(),
  ) {}
  handleError(error) {
    this.notificationService.displayCaughtError(error.message);
    throw error;
  }
}

header.component.ts

export class HeaderComponent implements OnInit {
  constructor(
    private snackBar: MatSnackBar,
    private notificationService: NotificationService,
    public auth: AuthService,
    private zone: NgZone,
  ) {}

  ngOnInit() {
    this.notificationService.displayError$.subscribe((error) => {
      // Load the given component into the snack-bar.
      this.zone.run(() => {
        this.snackBar.openFromComponent(NotificationSnackBarComponent, {
          data: {
            message: error,
          },
        });
      });
    });
  }
}

app.module.ts providers: [{ provide: ErrorHandler, useClass: LolPickemErrorHandler },]

The intention is: * an error is thrown * the error handler picks up the error and hits the displayErrorSource.next() on the notification.service * the header.component is subscribed to that, so it in turn creates the snack bar with .openFromComponent

and that all works correctly, the snack bar is displayed correctly.

Then, the dismiss button on the notification-snack-bar.component does not close the snack bar.

When I put a break point in the browser in the notification-snack-bar.component.ts file on the line this.snackBar._openedSnackBarRef.dismiss();, I can see that the code comes there and calls that method, but it does not do anything.

While trouble shooting, I have also expanded and tried the following in the notification-snack-bar-component.ts:

   this.snackBar._openedSnackBarRef.dismiss();
   this.snackBar.dismiss();
   this.snackBarRef.instance.snackBarRef.dismiss();
   this.snackBarRef.dismiss();

Any help would be greatly appreciated, this is driving me crazy!

Fyi, this it the repo I am working with (I just artificially threw an error in the Angular code): https://github.com/blubberbo/LolPickem

Upvotes: 0

Views: 1493

Answers (1)

blubberbo
blubberbo

Reputation: 4613

I did it!

In the lol-pickem-error.handler.ts, it used to read just:

export class LolPickemErrorHandler implements ErrorHandler {
  constructor(
    private notificationService: NotificationService = new NotificationService(),
  ) {}
  handleError(error) {
    this.notificationService.displayCaughtError(error.message);
  }
}

and then I added the throw error; after calling this.notificationService. displayCaughtError, because I still wanted the error to be logged in the console. Needless to say, that was a mistake and caused an a loop that made the snack bar not dismissable!

I changed it to read:

 handleError(error) {
    this.notificationService.displayCaughtError(error.message);
    console.error(error);
  }

and all is well in the kingdom again!

Upvotes: 1

Related Questions