15
/app
        - app.component.ts 
        - app.component.html (hide/show: menu bar)
        - app.global.service.ts (Public varible LoginSuccess:boolean)
        - main.ts
        /student
            - student.ts
            - student.service.ts
            - student.component.ts
            - student.component.html
        /security
            - login.component.ts (LoginSuccess = true)
            - login.component.html

In my application of Angular2, I have a simple need where I want to show hide menu bar based on login success. For that I created a service which just have a LoginSuccess boolean varilable, which I would set on login component and will use on app.component.html for [hidden]=LoginSuccess nav tag.

Problem I am facing is, even after injecting app.global.service.ts thru constructor of app.component.ts & login.component.ts value is not persisting and each constructor creating new object of app.global.service.ts.

Question: How can I achieve to persist single value across application thru service. Somewhere in Angular2 docs, I did read that Injectable service is singleton.

Sanket Makani
  • 2,491
  • 2
  • 15
  • 23
Avi Kenjale
  • 2,414
  • 6
  • 29
  • 46

5 Answers5

29

You should provide GlobalService at bootstrap, and not for each component:

bootstrap(AppComponent, [GlobalService])

@Component({
  providers: [], // yes
  // providers: [GlobalService], // NO.
})
class AppComponent {
  constructor(private gs: GlobalService) {
    // gs is instance of GlobalService created at bootstrap
  }
}

This way GlobalService will be a singleton.

For more advanced approach see this answer.

vosicz
  • 59
  • 6
Sasxa
  • 40,334
  • 16
  • 88
  • 102
  • and what about if we want to provide some components at the time of bootstrap, like we did in the Globalservice ? – Pardeep Jain Apr 08 '16 at 08:01
  • 1
    Just saying: If the component, to which you inject the singleton (global) service, is in a separate file, you nonetheless have to use an import statement in that file to load the service: `import {AuthService} from "./services/auth.service";` – Samuel Jul 05 '16 at 15:54
  • 7
    But if I don't add it to the providers:[] I get an error; EXCEPTION: No provider for GlobalService! – Jonas Törnqvist Aug 23 '16 at 16:42
  • @JonasTörnqvist, you should write "providers: [GlobalService]" in your NgModule decorator function. It solved this problem for me. – Ijon Tichy Jan 09 '17 at 12:18
  • 2
    How can I use it in angular for? Because I have the syntax in angular 4 in app.module is like this. `bootstrap: [ AppComponent ]` and when I add a service like this `bootstrap: [ AppComponent, SharedService ]` or `bootstrap: [ AppComponent, [SharedService] ]` I get an error that I can't add a service for bootstrapping like this. Can any one any idea about this? – Habib Oct 05 '17 at 11:25
7

You should have an app.component.ts and instead of boostrapping inside of app.module.ts you inject the service into app.component.ts.

...
import { MusicService } from './Services/music-service';

@Component({
    selector: 'app-root',
    templateUrl: 'app.component.html',
    providers: [MusicService],
    ...
})
export class AppComponent {

constructor(private MS: MusicService) {

}
...

This is based off the current Angular2 build. So inside index.html you should have <app-root> where AppComponent is loaded.

Now to use it inside any other component use just import it:

import { MusicService } from './Services/music-service';

and initialize it:

constructor(private MS: MusicService) {

}

Summary:

  1. Import into app.component.ts
  2. Insert into app.component.ts as a provider
  3. Initialize in constructor
  4. Repeat step 2,3 for every other component use wish to use it in

Reference: Angular Dependency Injection

theblindprophet
  • 7,767
  • 5
  • 37
  • 55
4

As Saxsa, the key point is to define your service provider within the application injector and not at each component level. Be careful not to define the service provider twice... Otherwise you will still have separate service instances.

This way you will be able to share the same instance of the service.

This behavior occurs because of hierarchical injectors of Angular2. For more details, you could have a look at this question:

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
4

As of final release (Angular 2.0.0) :

Import the service and inject it in the providers array like so :

import { GlobalService } from './app.global.service';

//further down:
@NgModule({
  bootstrap: [ App ],
  declarations: [
    // Your components should go here 
  ],
  imports: [ 
    // Your module imports should go here
  ],
  providers: [ 
    ENV_PROVIDERS // By Angular
    // Your providers should go here, i.e.
    GlobalService
  ]
});
mareks
  • 774
  • 6
  • 5
  • @Blauhim That's different from mareks' answer. The providers in mareks' code is global. The answer that you referenced was about instantiating a provider in each component. – Rax Weber Mar 28 '17 at 09:24
0

I will just add, because i was stuck at this point to, although i used a Singelton, you also have to use the Angular routing strategie:

You can't use href="../my-route"

cause this starts the whole application new:

instead you have to use: routerLink="../my-route"

SAM
  • 742
  • 10
  • 24