Ngx-toastr: Tostr messages not working. Script error in browser console.

Created on 16 Jun 2017  路  9Comments  路  Source: scttcper/ngx-toastr

Hi,

I followed the instructions to setup toastr as per the readme. Am using Angular version 4.1.3.
ngx-toastr version is 5.2.4

this.toastrService.success('Hello world!', 'Toastr fun!');

The above line is throwing the following exception in browser console:

dom-portal-host.js:45 Uncaught TypeError: Cannot read property 'attachView' of undefined at DomPortalHost.attachComponentPortal (dom-portal-host.js:45) at DomPortalHost.BasePortalHost.attach (portal.js:47) at OverlayRef.attach (overlay-ref.js:10) at ToastrService._buildNotification (toastr-service.js:152) at ToastrService.success (toastr-service.js:25)

Any help is greatly appreciated.

Thanks,
Hari

Most helpful comment

I've implemented something like this before. Here is what I've done:

app.error-handler.ts:

import { ErrorHandler, Inject, Injector, NgZone, isDevMode } from "@angular/core";
import { Response } from "@angular/http";
import { ToastrService } from "ngx-toastr";

import * as Raven from 'raven-js'

export class AppErrorHandler implements ErrorHandler {
    constructor(@Inject(NgZone) private ngZone: NgZone, @Inject(Injector) private injector: Injector) { }

    private get toastr(): ToastrService {
        return this.injector.get(ToastrService);
    }

    public handleError(error: any): void {
        this.ngZone.run(() => {
            let errorTitle = 'Error';
            let errMsg = 'An unexpected error ocurred';

            if (error instanceof Response) {
                const contentType = error.headers.get("Content-Type")

                if (contentType && contentType == "application/json") {
                    const body = error.json();
                    errorTitle = body.message || errorTitle;
                    errMsg = body.detailedMessage || JSON.stringify(body);
                } else {
                    errMsg = error.text();
                }
            }
            this.toastr.error(errMsg, errorTitle);
        });

        if (!isDevMode())
            Raven.captureException(error.originalError || error);
        else
            throw error;
    }
}

And then in app.module.ts:

@NgModule({
  // ... other imports, declarations, etc.
  providers: [
    { provide: ErrorHandler, useClass: AppErrorHandler },
    // ... other providers
  ]
})
export class AppModule {}

This is very similar to what you're doing. I'm not sure if NgZone is needed or not, it was working for HTTP error without it, but I decided to add it anyways, just in case.

All 9 comments

Can you show us the ng module where you're importing toastrmodule

Also a bit more on where you're using toastr service? In a component or service?

Hi @scttcper ,

Thanks for the reply.

My scenario is that I want to show a toastr error message when some exception occur in the application.
For this I implemented a GlobalExceptionHandler which will catch the exception and invoke the toastr service.

PFB the code I wrote:

`
//global.error.handler.service.ts

import { ErrorHandler, Injectable, Injector} from '@angular/core';
import {ToastrMessageService} from './toastr.service';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
private toastrService;
constructor(injector:Injector) {
this.toastrService = injector.get(ToastrMessageService);
}

handleError(error) {
    this.toastrService.error('Some error occurred', 'Error occurred');

    throw error;
}

}

//toastr.service.ts

import {Injectable} from '@angular/core';
import { ToastrService } from 'ngx-toastr';

@Injectable()
export class ToastrMessageService {
constructor(
private toastrService: ToastrService
) {

}

showError(message, heading) {
    if(message){
        this.toastrService.error(message, heading);
    }
}

}`

Hope this helps.

I've implemented something like this before. Here is what I've done:

app.error-handler.ts:

import { ErrorHandler, Inject, Injector, NgZone, isDevMode } from "@angular/core";
import { Response } from "@angular/http";
import { ToastrService } from "ngx-toastr";

import * as Raven from 'raven-js'

export class AppErrorHandler implements ErrorHandler {
    constructor(@Inject(NgZone) private ngZone: NgZone, @Inject(Injector) private injector: Injector) { }

    private get toastr(): ToastrService {
        return this.injector.get(ToastrService);
    }

    public handleError(error: any): void {
        this.ngZone.run(() => {
            let errorTitle = 'Error';
            let errMsg = 'An unexpected error ocurred';

            if (error instanceof Response) {
                const contentType = error.headers.get("Content-Type")

                if (contentType && contentType == "application/json") {
                    const body = error.json();
                    errorTitle = body.message || errorTitle;
                    errMsg = body.detailedMessage || JSON.stringify(body);
                } else {
                    errMsg = error.text();
                }
            }
            this.toastr.error(errMsg, errorTitle);
        });

        if (!isDevMode())
            Raven.captureException(error.originalError || error);
        else
            throw error;
    }
}

And then in app.module.ts:

@NgModule({
  // ... other imports, declarations, etc.
  providers: [
    { provide: ErrorHandler, useClass: AppErrorHandler },
    // ... other providers
  ]
})
export class AppModule {}

This is very similar to what you're doing. I'm not sure if NgZone is needed or not, it was working for HTTP error without it, but I decided to add it anyways, just in case.

Hi @yarrgh ,

I emulated your code snippet and it worked like a charm.
You made my day :)

Thanks,
Hari

Glad it worked for you!

@yarrgh the dependency injection wizard. I'll have to setup sentry in my app that way.

@yarrgh wow... thank you so much, i was losing hope.

i got the different error, so something is fishy, please owner look at this sir?

app.global.errorhandler.ts:20 Error: Uncaught (in promise): TypeError: Cannot read property 'create' of undefined
TypeError: Cannot read property 'create' of undefined
at ToastrService.push../node_modules/ngx-toastr/fesm5/ngx-toastr.js.ToastrService._buildNotification (ngx-toastr.js:1163)
at ToastrService.push../node_modules/ngx-toastr/fesm5/ngx-toastr.js.ToastrService._preBuildNotification (ngx-toastr.js:1114)
at ToastrService.push../node_modules/ngx-toastr/fesm5/ngx-toastr.js.ToastrService.error (ngx-toastr.js:906)
at AppGlobalErrorhandler. (app.global.errorhandler.ts:21)
at step (custom-http-client.ts:8)
at Object.next (custom-http-client.ts:8)
at custom-http-client.ts:8
at new ZoneAwarePromise (zone.js:891)
at push../src/app/_error/app.global.errorhandler.ts.__awaiter (custom-http-client.ts:8)
at AppGlobalErrorhandler.push../src/app/_error/app.global.errorhandler.ts.AppGlobalErrorhandler.handleError (app.global.errorhandler.ts:19)
at ToastrService.push../node_modules/ngx-toastr/fesm5/ngx-toastr.js.ToastrService._buildNotification (ngx-toastr.js:1163)
at ToastrService.push../node_modules/ngx-toastr/fesm5/ngx-toastr.js.ToastrService._preBuildNotification (ngx-toastr.js:1114)
at ToastrService.push../node_modules/ngx-toastr/fesm5/ngx-toastr.js.ToastrService.error (ngx-toastr.js:906)
at AppGlobalErrorhandler. (app.global.errorhandler.ts:21)
at step (custom-http-client.ts:8)
at Object.next (custom-http-client.ts:8)
at custom-http-client.ts:8
at new ZoneAwarePromise (zone.js:891)
at push../src/app/_error/app.global.errorhandler.ts.__awaiter (custom-http-client.ts:8)
at AppGlobalErrorhandler.push../src/app/_error/app.global.errorhandler.ts.AppGlobalErrorhandler.handleError (app.global.errorhandler.ts:19)
at resolvePromise (zone.js:814)
at new ZoneAwarePromise (zone.js:894)
at push../src/app/_error/app.global.errorhandler.ts.__awaiter (custom-http-client.ts:8)
at AppGlobalErrorhandler.push../src/app/_error/app.global.errorhandler.ts.AppGlobalErrorhandler.handleError (app.global.errorhandler.ts:19)
at dispatchEvent (core.js:7714)
at core.js:8154
at HTMLButtonElement. (platform-browser.js:988)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.js:3811)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)

Was this page helpful?
0 / 5 - 0 ratings