I am trying to use an app-wide service (UserService) that stores authenticated user details. I have set up some routes but found that UserService is instantiated per route. I want them to share the same UserService.
I have created a CoreModule containing TestService as provider and imported it into AppModule.
core.module.ts:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TestService } from '../test.service';
@NgModule({
imports: [
CommonModule
],
declarations: [],
providers: [
TestService
]
})
export class CoreModule { }
test.service.ts:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class TestService {
constructor() { console.log('testService constructor called');}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AdminComponent } from './layout/admin/admin.component';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { CoreModule } from './core/core.module';
@NgModule({
declarations: [
AppComponent,
AdminComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
CoreModule
],
providers: [
],
bootstrap: [AppComponent]
})
export class AppModule { }
app-routing.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';
import { BasicLoginComponent } from './basic-login/basic-login.component';
import { HttpClientModule } from '@angular/common/http';
import { AdminComponent } from './layout/admin/admin.component';
const routes: Routes = [
{
path: '',
component: AdminComponent,
children: [
{
path: 'home',
loadChildren: './dashboard/dashboard.module#DashboardModule'
},
{
path: 'user/profile',
loadChildren: './user-profile/user-profile.module#UserProfileModule'
}
]
},
]
@NgModule({
imports: [
CommonModule,
RouterModule.forRoot(routes),
HttpClientModule
],
exports: [
[RouterModule]
],
declarations: []
})
export class AppRoutingModule { }
I have injected the TestService into DashboardComponent and UserProfileComponent constructors. However, when routing between two of these components, the TestService constructor is called twice.
It seems so straightforward but somehow I can't get it right. Can anyone point me to the right direction to troubleshoot this?
*edit
dashboard.component.ts
import {AfterViewInit, Component, OnInit, ViewEncapsulation} from '@angular/core';
/*import {NotificationsService} from 'angular2-notifications';*/
import { UserService } from '../user.service.js';
import { LocalStorageService } from '../../../node_modules/ngx-webstorage';
import { TestService } from '../test.service.js';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class DashboardComponent implements OnInit, AfterViewInit {
constructor(private userService:UserService, private localSt:LocalStorageService,
private testService:TestService) { // private servicePNotify: NotificationsService
}
ngOnInit() {
}
}
user-profile-component.ts:
import {Component, OnInit} from '@angular/core';
import {animate, style, transition, trigger} from '@angular/animations';
import {Http} from '@angular/http';
import { TestService } from '../test.service';
@Component({
selector: 'app-user-profile',
templateUrl: './user-profile.component.html',
styleUrls: [
'./user-profile.component.scss',
'../../assets/icon/icofont/css/icofont.scss'
],
})
export class UserProfileComponent implements OnInit {
constructor(public http: Http, private userService: UserService,
private testService:TestService) {
}
ngOnInit() {
}
}
There are multiple ways to prevent this: Use the providedIn syntax instead of registering the service in the module. Separate your services into their own module. Define forRoot() and forChild() methods in the module.
The answer would be no. The main objective of angular services is to share data across Angular application. Practically an angular service can be shared between all the components or can be limited to some component.
Angular DI maintains a single instance per provider. In your case if you have two constructor parameters with the same type, they resolve to the same instance.
The providedIn allow us to specify how Angular should provide the dependency in the service class itself instead of in the Angular Module. It also helps to make the service tree shakable i.e. remove the service from the final bundle if the app does not use it.
As you have declared the TestService as -
@Injectable({
providedIn: 'root'
})
Which means you are adding to AppRoot module.
No need to add explicitly in the CoreModule
, so remove from providers of CoreModule
. Remove following -
providers: [
TestService
]
As you are adding the TestSevice
in CoreModule
which is already added in RootModule
that's the reason it constructor
getting called multiple times.
So use either of one from above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With