3

I've recently migrated to Angular 2 RC 5 and converted the sub-modules in my app to NgModule.

Given the following plunker provided in the Angular2 Routing Documentation, how can the CrisisService in the CrisisCenterModule be turned into a stateful singleton that is share across the routes of the crisis-center module.

Currently a new CrisisService is instantiated for every route in the module.

e.g. if you add a simple constructor in the CrisisService, like so:

constructor() {
  console.log("Hello from CrisisService");
}

The browser console will log out that string every time you link to a different sub-route, e.g. /crisis-center or /crisis-center/11

I'd like to be able to share state across the components in a module via a service that is cleared whenever you route away from this module, without moving the service into a global shared model.

Thank You

  • I found a solution providing the service in the RootModule (AppModule) and not in the Submodule (CrisisCenterModule). I do now know if it is a bug or if it is the right behaviour. If you find any documentation about this, please, let me know or I'll open an issue in the Angular2 github repo. – Bruno João Aug 22 '16 at 20:19
  • I made a plunker to show the case http://plnkr.co/edit/iy6zV9NJL3r8EtcqvRqU – Bruno João Aug 23 '16 at 14:20
  • @vinagreti I've opened an [issue](https://github.com/angular/angular/issues/11125) on the angular2 github repo. –  Aug 28 '16 at 07:46
  • I think this issue is still persist. Or may be I am doing any specific configuration mistake. Here is my another question with same topic http://stackoverflow.com/questions/40981306/service-is-not-being-singleton-for-angular2-router-lazy-loading-with-loadchildre – Partha Sarathi Ghosh Dec 05 '16 at 18:56

2 Answers2

1

Edited answer 2016 Dec 05 at 11:14:

The problem was a bug and was fixed in https://github.com/angular/angular/issues/11125.

So, now you can load the service at any module, not only in the app, and you will have a singleton for it's children.

Old answer - 2016 Aug 22 at 20:20:

I found a solution providing the service in the RootModule (AppModule) and not in the Submodule (CrisisCenterModule).

I do now know if it is a bug or if it is the right behaviour.

If you find any documentation about this, please, let me know or I'll open an issue in the Angular2 github repo.

Bruno João
  • 5,105
  • 2
  • 21
  • 26
  • 1
    Is it a lazy-loaded module? Then you need `forRoot()` otherwise it should be the default (application-wide singleton). – Günter Zöchbauer Aug 23 '16 at 05:11
  • It is a lazy-load module. But I did not understand where to call the `forRoot()` method. I did this plunker to show the problem. Maybe you can edit it to solve this. http://plnkr.co/edit/iy6zV9NJL3r8EtcqvRqU thanks – Bruno João Aug 23 '16 at 14:15
  • @GünterZöchbauer, can you change this plunker to use `forRoot()` method? http://plnkr.co/edit/iy6zV9NJL3r8EtcqvRqU – Bruno João Aug 23 '16 at 16:06
  • I am also looking for the answer of this problem. I do not want to put my child module services to app module. Then I can not keep loosely coupled feature. – Partha Sarathi Ghosh Dec 05 '16 at 08:46
  • @ParthaSarathiGhosh, this was fixed in https://github.com/angular/angular/issues/11125 – Bruno João Dec 05 '16 at 11:10
  • I think Still the issue is there in version 2.2.1 – Partha Sarathi Ghosh Dec 05 '16 at 11:28
  • @ParthaSarathiGhosh Actually it is already fixed, I've checked this in one of my apps. Maybe you are having another problem. Can you place a new question in SO with your scenario? Put your model structure, so we can better understand your app. I think that is the better way to help you find a solution. Plunks is not acce – Bruno João Dec 05 '16 at 12:15
  • Actually I am trying to create a plunker for that. But I am facing different problem for lazy loading in plunker. Here is the Plunker https://plnkr.co/edit/zgMigHSEFXxxwUp8QQzr?p=preview and here is the question. Which is I am facing now. http://stackoverflow.com/questions/40971268/how-to-create-plunker-for-angular2-lazyloading-router-with-loadchildren – Partha Sarathi Ghosh Dec 05 '16 at 12:23
  • Here is my new question. Can you please check it out. http://stackoverflow.com/questions/40981306/service-is-not-being-singleton-for-angular2-router-lazy-loading-with-loadchildre – Partha Sarathi Ghosh Dec 05 '16 at 18:54
0

Like m32da1 says, the Service is only used in the CrisisCenterModule. What I did lazy load my routes:

export const routes: Routes = [ 
{ path: '', redirectTo: 'login', pathMatch: 'full' }, 
{ path: 'crisis', loadChildren: 'app/crisis-center/crisisCenter.module' } 
...

and add the CrisisServices as a provider in the crisisCenter module

If you are planning to use it in other components/routes as well, you can make it an singleton: https://angular.io/docs/ts/latest/guide/ngmodule.html#!#shared-module-for-root

Add a shared.module.ts

import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule }        from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HeroesModule } from './heroes/heroes.module';
import { LoginComponent } from './login.component';
import { DialogService }  from './dialog.service';
import { CrisisService }  from './crisis-center/crisis.service';
@NgModule({
    imports: [CommonModule, FormsModule, RouterModule ],
    declarations: [],
    exports: [
        CommonModule, FormsModule, RouterModule]
})
export class SharedModule {

    static forRoot(): ModuleWithProviders {
        return {
            ngModule: SharedModule,
            providers: [DialogService, CrisisService],
        };
    }
}

And add the SharedModule.forRoot to the imports in the app.module.ts:

import { NgModule }       from '@angular/core';
import { BrowserModule }  from '@angular/platform-browser';
import { FormsModule }    from '@angular/forms';

import { AppComponent }       from './app.component';
import { routing,
         appRoutingProviders } from './app.routing';

import { HeroesModule } from './heroes/heroes.module';

import { LoginComponent } from './login.component';

import { DialogService }  from './dialog.service';

@NgModule({
  imports: [
    BrowserModule,
    SharedModule.forRoot(),
    routing,
    HeroesModule
  ],
  declarations: [
    AppComponent,
    LoginComponent
  ],
  providers: [
    appRoutingProviders
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {
}
Marcel Hoekstra
  • 1,334
  • 12
  • 19
  • Marcel, can you provide some plunker with your solution? Where to call the forRoot method? – Bruno João Aug 22 '16 at 20:44
  • 1
    The CrisisService is really only used by the CrisisCenterModule, so elevating it to the app scope would defeat the purpose, i.e. the CrisisService must unload when then user routes to a different module, like the HeroModule. –  Aug 22 '16 at 22:46