Search code examples
javascriptangularerror-handlingmodal-dialoginject

How to show a bootstrap modal via an Angular-Service


I have a global Errorhandler in which I process Client- and Server-Errors.

To provide a feedback for the user I want to open a modal which returns the error-message.

Therefore I've implemented a modal:

import {Component} from '@angular/core';
import {BsModalRef, BsModalService} from 'ngx-bootstrap';
import {Button} from '../../layout-models/button.model';

@Component({
  selector: 'error-modal',
  templateUrl: './error-modal.component.html',
  styleUrls: ['./error-modal.component.scss']
})
export class ErrorModalComponent {
  title: string;
  buttonTitle = 'OK';
  type: 'error';
  button: Button;

  protected modalRef: BsModalRef;

  constructor(protected modalService: BsModalService) {}

  public show(title: string, message: string) {
    this.title = title;
    this.modalRef = this.modalService.show(
      message,
      Object.assign({}, { class: `modal-banner ${this.type}`})
    );
  }

  hide() {
    if (this.modalRef) {
      this.modalRef.hide();
    }
  }
}

In my Notification-Service:

import {Injectable, NgZone} from '@angular/core';
import { ErrorModalComponent } from '../error-modal.component';

@Injectable({
  providedIn: 'root'
})
export class NotificationService {

  public errorModalComponent: ErrorModalComponent;

  showError(title: string, message: string): void {
     this.errorModalComponent.show(title, message);
  }
}

Which leads to Uncaught TypeError: Cannot read property 'show' of undefined

I feel like I am doing some fundamental mistake - the main purpose of this is to have a centralized modal. Is this possible or do I need to use the ModalComponent in every Component in which I want to show the error-handling-modal?


Solution

  • I wouldn't use ngx-modal I would use NgbModal

    What yazantahhan means is something like this:

    import {Injectable} from "@angular/core";
    import {NgbModal, NgbModalRef} from "@ng-bootstrap/ng-bootstrap";
    
    @Injectable()
    export class ErrorModalService {
    
      title: string;
      buttonTitle = "OK";
      type: "error";
    
      protected modalRef: NgbModalRef;
    
      constructor(protected modalService: NgbModal) {}
    
      public show(title: string, message: string) {
        this.title = title;
        this.modalRef = this.modalService.open(
          message
        );
      }
    
      hide() {
        if (this.modalRef) {
          this.modalRef.close();
        }
      }
    }
    Then inject and use it like this:

    import { Component } from "@angular/core";
    import {ErrorModalService} from "./ErrorModalService";
    
    @Component({
      selector: "app-root",
      templateUrl: "./app.component.html",
      styleUrls: ["./app.component.scss"]
    })
    export class AppComponent {
      title = "testAngular";
    
      constructor(
        private errorModalService: ErrorModalService,
      ) {}
    
    
      showError() {
        this.errorModalService.show("title", "message");
      }
    }

    Don't forget to provide the service in your module

    import { BrowserModule } from "@angular/platform-browser";
    import { NgModule } from "@angular/core";
    
    import { AppRoutingModule } from "./app-routing.module";
    import { AppComponent } from "./app.component";
    import {ErrorModalService} from "./ErrorModalService";
    import {BsModalService} from "ngx-bootstrap/modal";
    import {NgbModule} from "@ng-bootstrap/ng-bootstrap";
    
    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule,
        AppRoutingModule,
        NgbModule,
      ],
      providers: [
        ErrorModalService,
      ],
      bootstrap: [AppComponent],
    })
    export class AppModule { }