You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior
After upgrading to router 3.2.0, services being provided by component module are being instantiated twice. Once while resolver is being run (last place in router is PreActivation.prototype.getToken) and then again later during activation (last place in router is RouterOutlet.prototype.activate).
Upgrading rest of Angular to 2.2.0 and leaving router at 3.1.1 it works as it used to (and looking in debugger I see service is only instantiated from PreActivation.prototype.getToken)
Expected behavior
Providers should only be instantiated once - as they are when using router version 3.1.1
Minimal reproduction of the problem with instructions
Haven't yet reproduced in a plnkr but my use case has a lazy loaded component that itself has sub components (not lazy loaded). The sub component has a resolver that uses a service, and the sub component itself uses the service. The service is included in the lazy loaded components module providers list and is being instantiated twice. Once apparently while router is working on resolve and once when component is being activated.
What is the motivation / use case for changing the behavior?
Its just wrong, and my service fetches data on initialization so extra instance causes extra fetch. This does not happen with router 3.1.1 (never tried 3.1.2 as deactivate guards don't work correctly in that version)
Please tell us about your environment:
Windows 10, Visual Studio Code, angular-cli: 1.0.0-beta.19-3 ng serve
Angular version: 2.0.X
2.2.0
Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
Modified an existing simple repo I made for a different issue - https://github.com/slubowsky/routing-angular-cli. Run the app (ng serve) and click the "lazy" link. You will see the FooService constructor is called twice. It shouldn't be.
Change router to 3.1.1 and rerun. The constructor is only called once.
Ok just deleted most of what was there (there wasn't much). Its pretty bare bones now. A top level app component and one lazy loaded child. The child is the default route and is loaded on startup. You can see my console.log message from the service constructor twice. Change to router 3.1.1 it and only appears once.
Attached is a angular-cli project which exactly reproduces the bug as I see it.
It has a lazy route which, when loaded, leads to the module being loaded twice, as is shown by the console.log() in the src/app/lazy.module.ts file: router-bug.zip
In order to run, use:
npm install angular-cli -g
npm install
ng serve
goto localhost:4200/
click on the "Call me Lazy" link
We strongly depend on the Angular team fixing this bug, and I am quite amazed that all we get in response is: "Pls add a repro in plunkr."
Reacted by Antony Budianto, Kevin Schneider, Guido Gustavo Pollitzer, Abbass Samaha, Fidel, Ricardo Varanda and aashkashah
If there is something wrong in my declarations which explains that, please tell me what.
IF not, do you have a workaround in mind while I need my singletons to be singletons.. It's the basis !
@rlegrand ... ah, ok, I understand ... but I still think that the idea of I have a module which provides services is more recombined as it should be ... especially with just singleton providers ... so I recommend to include them directly to providers section of the app module.
With other parts ... like components, pipes, ... the idea of core module is still fine.
@sijucm You're providing UserService inside CustomerComponents so the service follow the lifecycle of the component: it is created each time a customer component is created and destroyed when the component is destroyed.
Issues tracker is not meant to provide support so please use stackoverflow or gitter next time you need help.
There is an answer on stackoverflow to prevent services in a shared module to be instantiated multiple times that worked for me and wasn't mentioned here:
Implement forRoot() on that shared module and only add providers there. In app module import shared module with forRoot() and in all feature modules (lazy or note) use the SharedModule without forRoot().
@gruppjo Is there some recommended approach to handle cases where the app is not small and the size of the singleton providers is not trivial to load all of them in the initial load?
In most cases I see, providers are supposed to be singletons (except for some specific cases). For small apps this approach may seem fine, but as the app grows you end up declaring a lot of providers in AppModule, making the initial load size larger and consequently slower.
Also, this doesn't seem a good approach with libraries because you would have to load all the libraries providers (or most of them) in the initial load (in AppModule).
Is there some recommendation regarding that? Like defining one global provider that store the state of other providers and import it in AppModule and import all other providers only where they are used (accessing the global provider to retrieve and define state, instead of relying in itself). Or something along these lines?
Otherwise it might become difficult to maintain the performance of angular apps as the app size grows.
I agree, it is very misleading. After reading documentation I had clear conviction that services declared in modules are singletons, so I don't understand why it behaves differently for lazy loaded modules. At the very least this behavior should be described in documentation. Admittedly, there is this statement in docs:
"Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root"
but, as far as I'm concerned, for now, it is the only way, not the 'preffered way'.
Activity
DzmitryShylovich commentedon Nov 14, 2016
Pls add a repro in plunkr.
slubowsky commentedon Nov 14, 2016
Modified an existing simple repo I made for a different issue - https://github.com/slubowsky/routing-angular-cli. Run the app (ng serve) and click the "lazy" link. You will see the FooService constructor is called twice. It shouldn't be.
Change router to 3.1.1 and rerun. The constructor is only called once.
vicb commentedon Nov 15, 2016
Could you reduce your repo to only the things required for demonstrating the issue
slubowsky commentedon Nov 15, 2016
Ok just deleted most of what was there (there wasn't much). Its pretty bare bones now. A top level app component and one lazy loaded child. The child is the default route and is loaded on startup. You can see my console.log message from the service constructor twice. Change to router 3.1.1 it and only appears once.
thaoula commentedon Nov 15, 2016
It seems to running providers starting with twice, then 3 times, then 4 times etc ... each time you go into a Lazy Loaded route.
I started seeing this effect when watch network requests as soon as updated to 3.2.0 of the router. 3.1.0 version has no problems.
serhiisol commentedon Nov 17, 2016
I got the same problem, module constructor executed twice for lazy loaded route
Plunker example
In console you'll see
Login Modulelog was executed twicehttpdigest commentedon Nov 25, 2016
Having the exact same problem as described by @serhiisol after upgrading from Angular 2.1.2 and Router 3.1.2 to Angular 2.2.3 and Router 3.2.3.
thaoula commentedon Nov 27, 2016
Hi Guys,
We need to start using some new features on FormGroup (2.2.0) but are blocked by this issue.
Can someone from the Angular team advise when this will be resolved. The issue appears to exist in 2.2.3 and the latest 2.3.0 beta.
Regards,
Tarek
httpdigest commentedon Nov 29, 2016
Attached is a angular-cli project which exactly reproduces the bug as I see it.
It has a lazy route which, when loaded, leads to the module being loaded twice, as is shown by the console.log() in the
src/app/lazy.module.tsfile:router-bug.zip
In order to run, use:
We strongly depend on the Angular team fixing this bug, and I am quite amazed that all we get in response is: "Pls add a repro in plunkr."
JBusch commentedon Nov 29, 2016
Same problem here.
antonybudianto commentedon Nov 30, 2016
This kind of bug should be put to high priority I think, need patch update soon
Dunos commentedon Nov 30, 2016
I thought I was the only one with this issue but clearly I'm not, let's hope they fix it soon :/
Btw I also have another plnkr, just in case (modified tour of heroes, just click the Heroes button and you can see the 2 calls in the console)
71 remaining items
jonathanborges commentedon Oct 26, 2017
Does'not work for me with
PreloadAllModulesdisabled.Using
loadChildrenandforChildroutes on child modules.Angular 4.3.4
rlegrand commentedon Feb 3, 2018
I maybe miss something, but for me it's not fixed in all cases.
In the app below:
=> The service is instantiaited twice.
https://stackblitz.com/edit/angular-7sqt76
Run the app and look at logs.
If there is something wrong in my declarations which explains that, please tell me what.
IF not, do you have a workaround in mind while I need my singletons to be singletons.. It's the basis !
mlc-mlapis commentedon Feb 3, 2018
@rlegrand ... I can't imagine why you should provide the singleton in the core module and not directly in the app module but if you want to do it in any reason ... you need to use the following syntax ... https://stackblitz.com/edit/angular-7sqt76-2hidqf?file=app%2Fmodules%2Fcore%2Fcore.module.ts
ldex commentedon Feb 3, 2018
Hi @rlegrand, what you get is the expected behavior.
To achieve your scenario you have to use the for root() technic.
Please have a look at the doc: https://angular.io/guide/singleton-services
rlegrand commentedon Feb 3, 2018
Hi,
Thank you guyz.
Without this answer, I would probably have used a static attribute in my service to be sure to manage only one instance"manually".
@mlc-mlapis I called it core module and includes it in the app for the example, in fact I just mean "I have a module which provides services"
Thank you.
mlc-mlapis commentedon Feb 3, 2018
@rlegrand ... ah, ok, I understand ... but I still think that the idea of
I have a module which provides servicesis more recombined as it should be ... especially with just singleton providers ... so I recommend to include them directly toproviderssection of the app module.With other parts ... like components, pipes, ... the idea of
core moduleis still fine.ghetolay commentedon Mar 2, 2018
@sijucm You're providing
UserServiceinsideCustomerComponentsso the service follow the lifecycle of the component: it is created each time a customer component is created and destroyed when the component is destroyed.Issues tracker is not meant to provide support so please use stackoverflow or gitter next time you need help.
gruppjo commentedon Apr 9, 2018
There is an answer on stackoverflow to prevent services in a shared module to be instantiated multiple times that worked for me and wasn't mentioned here:
Implement
forRoot()on that shared module and only add providers there. In app module import shared module withforRoot()and in all feature modules (lazy or note) use theSharedModulewithoutforRoot().https://stackoverflow.com/questions/41290275/angular2-lazy-loading-service-being-instantiated-twice
lucasbasquerotto commentedon Apr 20, 2018
@gruppjo Is there some recommended approach to handle cases where the app is not small and the size of the singleton providers is not trivial to load all of them in the initial load?
In most cases I see, providers are supposed to be singletons (except for some specific cases). For small apps this approach may seem fine, but as the app grows you end up declaring a lot of providers in
AppModule, making the initial load size larger and consequently slower.Also, this doesn't seem a good approach with libraries because you would have to load all the libraries providers (or most of them) in the initial load (in AppModule).
Is there some recommendation regarding that? Like defining one global provider that store the state of other providers and import it in
AppModuleand import all other providers only where they are used (accessing the global provider to retrieve and define state, instead of relying in itself). Or something along these lines?Otherwise it might become difficult to maintain the performance of angular apps as the app size grows.
Update: with Angular 6
providedIn: 'root'(https://angular.io/guide/singleton-services), it seems the problem with singleton providers is solved (for me, at least).anth-git commentedon Jul 4, 2018
I agree, it is very misleading. After reading documentation I had clear conviction that services declared in modules are singletons, so I don't understand why it behaves differently for lazy loaded modules. At the very least this behavior should be described in documentation. Admittedly, there is this statement in docs:
"Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root"
but, as far as I'm concerned, for now, it is the only way, not the 'preffered way'.
ilyes-hamrouni commentedon Jan 27, 2019
I have the problem but i am not working with any modules except the app.module.ts, please check my case.
https://stackoverflow.com/questions/54391955/angular-service-have-multiple-instances-instead-of-singleton/54392133?noredirect=1#comment95596734_54392133
angular-automatic-lock-bot commentedon Sep 14, 2019
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.