scttcper / ngx-toastr

🍞 Angular Toastr
https://ngx-toastr.vercel.app
MIT License
2.52k stars 359 forks source link

cannot read properties of undefined (reading "toastrService") #997

Open karthi-the-programmer opened 1 year ago

karthi-the-programmer commented 1 year ago

Getting the below error when inject the toaster service in another service file.

image

on version 13.2.1

amariq commented 1 year ago

Yeah, that's because Overlay service used by ToastrService injects the Angular's ApplicationRef inside constructor. Meaning if you try to inject the toastr before the ApplicationRef is initialized it will result in deps cycle (or silent fail, as in your case, it seems), and the ErrorHandler is being created exactly before that moment.

The easy solution: instead of directly injecting the toastr, use injector.get(ToastrService) manually for this case. It works, but the topics like this will continue popping up until it actually handled properly (like #917, #804, #327, #179, #137 and so on).

The best solution: the author should use injector.get(ApplicationRef) inside the Overlay service when needed instead of inject(ApplicationRef) at creation time. It would fix the root of problem once and for all, no more strange toastr is undefined and this._appRef.attachView is not a function errors for everyone.

passee commented 1 year ago

Got the same issue. even with injector it tells me toastrservice is undefined with angular cli v16

Cannot read properties of undefined (reading 'toastrService')

    export class WebAPIService {

constructor(private httpClient: HttpClient, @Inject(Injector) private injector: Injector) {}

config: Config;

headers = {
    "Cache-Control": "no-cache, no-store, must-revalidate, post-check=0, pre-check=0",
    Pragma: "no-cache",
    Expires: "0",
};

async getConfig() {
    this.config = await firstValueFrom(this.httpClient.get<Config>("assets/config.json", { headers: this.headers }));
}

getMatchingPartners(search: string, explicitSearchList: ExplicitSearch[]) {

    return this.httpClient
        .get<DataInterface[]>(
            this.config.ServerUrl + `x/x?search=${search}&explicitSearch=${JSON.stringify(explicitSearchList)}`,
            {
                headers: { "Content-Type": "text/plain; charset=utf-8" },
                responseType: "json",
                observe: "body",
                reportProgress: true,
                withCredentials: false,
            }
        )
        .pipe<any>(catchError(this.handleError));
}

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

private handleError(error: any) {
    this.toastrService.error("An unexpected error has occurred.", "Error", {
        closeButton: true,
        timeOut: 5000,
        onActivateTick: true,
    });
    return error;
}

} edit: the injection works, but the issue is trying to use toastrService in the handleError(). it seems that in this context toastrservice is undefined for some reason

amariq commented 1 year ago

@passee The problem in your case is just method context binding — use

catchError(this.handleError.bind(this))

or

catchError(error => this.handleError(error))