Angular Service singleton constructor called multi

2020-07-04 05:21发布

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

  }

}

2条回答
老娘就宠你
2楼-- · 2020-07-04 06:01

@Injectable({ providedIn: 'root' })

  • The providedIn with root option means, the service is available throughout the application as singleton service.
  • It doesn't complain any error like No provider for xxxservice bcz of providedIn if you didn't added to providers list of any module.
  • If you do adding to the list will leads to creating a new instance of service, which will give you wrong results than expected.

NOTE : Please make sure to use the concept for better results.

查看更多
Juvenile、少年°
3楼-- · 2020-07-04 06:07

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.

查看更多
登录 后发表回答