Skip to content

Router 3.2.0 - Providers instantiated twice #12869

Closed

Description

@slubowsky

I'm submitting a ... (check one with "x")

[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 ]

Only tried in Chrome

  • Language: [all | TypeScript X.X | ES6/7 | ES5]
    Typescript 2.0.9

  • Node (for AoT issues): node --version =

Activity

  1. DzmitryShylovich commented on Nov 14, 2016

    @DzmitryShylovich
    Contributor

    Pls add a repro in plunkr.

  2. slubowsky commented on Nov 14, 2016

    @slubowsky
    Author

    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.

  3. vicb commented on Nov 15, 2016

    @vicb
    Contributor

    Could you reduce your repo to only the things required for demonstrating the issue

  4. slubowsky commented on Nov 15, 2016

    @slubowsky
    Author

    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.

  5. thaoula commented on Nov 15, 2016

    @thaoula

    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.

  6. serhiisol commented on Nov 17, 2016

    @serhiisol

    I got the same problem, module constructor executed twice for lazy loaded route

    Plunker example

    In console you'll see Login Module log was executed twice

  7. httpdigest commented on Nov 25, 2016

    @httpdigest

    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.

  8. thaoula commented on Nov 27, 2016

    @thaoula

    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.

    • Are there any known workarounds?
    • Is it something we need to change in our code?

    Regards,
    Tarek

  9. httpdigest commented on Nov 29, 2016

    @httpdigest

    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."

  10. JBusch commented on Nov 29, 2016

    @JBusch

    Same problem here.

  11. antonybudianto commented on Nov 30, 2016

    @antonybudianto

    This kind of bug should be put to high priority I think, need patch update soon

  12. Dunos commented on Nov 30, 2016

    @Dunos

    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)

  13. 71 remaining items

  14. jonathanborges commented on Oct 26, 2017

    @jonathanborges

    Does'not work for me with PreloadAllModules disabled.

    Using loadChildren and forChild routes on child modules.

    Angular 4.3.4

  15. rlegrand commented on Feb 3, 2018

    @rlegrand

    I maybe miss something, but for me it's not fixed in all cases.
    In the app below:

    • the app has a dependency to a core module
    • the app lazily loads a "lazy" module
    • the lazy module has a dependency to the core module
    • both the app module and the lazy module use the singleton service provided in the core module
      => 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 !

  16. mlc-mlapis commented on Feb 3, 2018

    @mlc-mlapis
    Contributor

    @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

  17. ldex commented on Feb 3, 2018

    @ldex

    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

  18. rlegrand commented on Feb 3, 2018

    @rlegrand

    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.

  19. mlc-mlapis commented on Feb 3, 2018

    @mlc-mlapis
    Contributor

    @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.

  20. ghetolay commented on Mar 2, 2018

    @ghetolay
    Contributor

    @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.

  21. gruppjo commented on Apr 9, 2018

    @gruppjo

    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().

    https://stackoverflow.com/questions/41290275/angular2-lazy-loading-service-being-instantiated-twice

  22. lucasbasquerotto commented on Apr 20, 2018

    @lucasbasquerotto

    @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.

    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).

  23. anth-git commented on Jul 4, 2018

    @anth-git

    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'.

  24. ilyes-hamrouni commented on Jan 27, 2019

    @ilyes-hamrouni

    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

  25. angular-automatic-lock-bot commented on Sep 14, 2019

    @angular-automatic-lock-bot

    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.

  26. locked and limited conversation to collaborators on Sep 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions