Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow import ToastrModule without forRoot #415

Closed
aitorllj93 opened this issue Apr 17, 2018 · 14 comments · Fixed by #540
Closed

Allow import ToastrModule without forRoot #415

aitorllj93 opened this issue Apr 17, 2018 · 14 comments · Fixed by #540

Comments

@aitorllj93
Copy link

Hi, I've found that your library doesn't allow importing ToastrModule multiple times.

I would like to know why you don't support this feature. Most of the hybrids modules I've seen allow importing declarations on SharedModule and use forRoot for providers. Your module seems to do the same thing but the code on it's constructor disallows this feature.

@tomgruszowski
Copy link

tomgruszowski commented Apr 19, 2018

+1 for this. I'm wrapping your module and adding some defaults for our internal components library. Adding this in root app forces this package to be directly installed whereas I simply want this as a dependency of my custom lib so end developers install 1 package vs 10.

@trevor-hackett
Copy link
Collaborator

trevor-hackett commented Jul 18, 2018

The main reason this isn't currently allowed is because this can cause unexpected behavior if you try to change the global config in 2 different modules.

If you call ToastrModule.forRoot() in a module that gets loaded after another module has already called ToastrModule.forRoot(), and then try to set global options, they won't get applied. Whatever module calls forRoot() first wins. Even if no configuration is overridden, subsequent modules cannot modify the global config using forRoot().

@seanbotha123
Copy link

Hi @yarrgh, while your explanation does make sense, why not go the route of something like ng-bootstrap where you have only the base module declaring with forRoot, and any other modules would not use forRoot?

This gives the base module the ability to set the global config, while the other modules simply use the global config?

If you have a look here they explain it: https://ng-bootstrap.github.io/#/getting-started.

@trevor-hackett
Copy link
Collaborator

I see what you mean. Maybe instead of protecting against having forRoot() called multiple times by ensuring that the module is only created once, we should just check to see if forRoot() has already been called and throw an error.

Just curious as to why you want to import ToastrModule in a shared module. Are you using any of the component/directives in other modules?

@gregkopp
Copy link

gregkopp commented Aug 2, 2018

I have a project in which my notification service is in a shared module. My ToastrModule.forRoot() import is in the shared module only. When I start the app (that consumes the shared module). When I start my app, I get this error message:

Error: ToastrModule is already loaded. It should only be imported in your application's main module.

However, I am only loading the shared module once. I would hope this can get fixed soon.

@chrisj-au
Copy link

+1

I have my interceptors in my core module, as part of my error interceptor I want it to throw a toastr error on any http error response. I can't seem to get it working although I am new to splitting my application into modules. If I add toastr to my interceptor I get: NullInjectorError: No provider for ToastrService!. When I add ToastrModule to my core.module I get 'ToastrModule is already loaded' (it's not imported in app.module).

@trevor-hackett
Copy link
Collaborator

trevor-hackett commented Aug 8, 2018

@chrisjau Move your import from your shared module (or wherever it is being imported) into your core module.

Honestly, I'm having a hard time understanding the benefit of allowing ToastrModule to be imported without forRoot(). The only thing I can think of would be to allow all modules (if imported in a shared module) to have access to the components in ToastrModule. Honestly I cannot think of a use case any application would want from this.

When you call forRoot() it sets up ToastrService to be injectable globally throughout your application. A module doesn't need to have (and shouldn't have) ToastrModule imported to be able to get access to ToastrService. The only solution I can think of is to allow forRoot() to be called multiple times, which would allow it to be imported into a shared module. However, this can cause confusion (see my comment) if someone tries to call forRoot() from multiple modules as it wouldn't behave the way they'd expect.

ToastrModule.forRoot() doesn't have to be imported in your AppModule, It can be imported into any core module you choose (core = imported just once). Just be aware that if the module you choose is included in a lazy loaded module, ToastrService won't be available until that module is loaded.

@chrisj-au
Copy link

It seems irrespective of whether forRoot is used or not. If I remove the references below, and only add toastr to a lazy loaded feature module (by directly invoking it on subscribe() it works). Again I can't discount i'm doing something wrong. I have no shared module at this stage. Core.module is eager loaded in app.module and the interceptor lives in core.module so there are no lazy loaded modules in play with the setup I desire. If you aren't sure why it's breaking I don't want to waste any more of your time. thanks

core.module.ts
import { ToastrModule } from 'ngx-toastr';
imports: [ ToastrModule ] // or ToastrModule.forRoot() - same console error..

error interceptor:
import { ToastrService } from 'ngx-toastr';
constructor(private toastr: ToastrService) { super(); }
...
private ErrorHandler(error: HttpErrorResponse) {
this.toastr.error(error.message || 'Server error', null, this.toastrConfig);
}

app.module
import { CoreModule } from './core/core.module';

imports: [ CoreModule.forRoot() ]

@trevor-hackett
Copy link
Collaborator

@chrisjau your issue is different from this issue. I believe the issue you're seeing is caused from ToastrService not being available yet when trying to inject into your interceptor. See #179 (comment) for an example of how to fix your issue. If you're still having issues, open a new issue.

@pinalpatel06
Copy link

I have two projects in application. I have added ToastrModule in one app's CoreModule & export it. it is working fine. But when I added ToastrModule in another app's CoreModule, it gives error that (It is already imported. Add ToastrModule to Application main module.).
Any suggestions on this error??

@trevor-hackett
Copy link
Collaborator

Do they share a core module at all?

@pinalpatel06
Copy link

@yarrgh, No both projects have different CoreModule

@scttcper
Copy link
Owner

🎉 This issue has been resolved in version 9.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@mohammmedimran
Copy link

Hi
i am using ToastModule.root(Component) if i want to use default component also how can i use

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants