1

I am new to Angular and am trying to figure out how to inject my Angular service (game service) into another angular service which will be a Resolver (game resolver). Only one instance of my game service is typically created in my application and I am injecting it into each of my components successfully, but when my game resolver service is needed, it creates a new instance of the game service, even though the game service is supposed to be a singleton.

I've tried declaring both services in the 'providers' array of my NgModule, to try to make them both singleton services and I've also tried the approach of of declaring 'providedIn: 'root' in the @Injectable decorator, but a new instance of the game service is created when the game resolver service constructor is called.

//GameResolver.service.ts

    @Injectable({
      providedIn: 'root'
    })
    export class GameResolverService implements Resolve<Game> {
      constructor(private gameService: GameService) {

      }


      resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Game> {

          return this.gameService.getGameById(gameId)

      }
    }

//game-resolver.service.spec.ts    

import { TestBed, inject } from '@angular/core/testing';

import { GameResolverService } from './game-resolver.service';

describe('GameResolverService', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [GameResolverService]
    });
  });

  it('should be created', inject([GameResolverService], (service: GameResolverService) => {
    expect(service).toBeTruthy();
  }));
});



//Game.service.ts

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Game } from './game';
import { map } from "rxjs/operators";
import { User } from './user';


@Injectable({
  providedIn: 'root'
})
export class GameService {

  constructor(private http: Http) {
    console.log('new instance of GameService created');
  }



//app.module.ts

const appRoutes: Routes = [
  ...
  {path:'game', component: GameComponent, data:{depth:3}, resolve: { game: GameResolverService}},
  {path:'endGame', component: EndGameComponent, data:{depth:4}},
  {path:'nextRound', component: NextRoundComponent, data:{depth:5}}
]

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
  ],
  bootstrap: [AppComponent],
  providers: [GameService, GameResolverService]
})


//create-game.component.ts
...
import {GameService} from '../game.service';




@Component({
  selector: 'app-create-game',
  templateUrl: './create-game.component.html',
  styleUrls: ['./create-game.component.css'],

})
export class CreateGameComponent implements OnInit {
  // @HostListener('window:popstate', ['$event'])




  constructor(private gameService: GameService, private router: Router) {
   }


//game.component.ts

@Component({
  selector: 'app-game',
  templateUrl: './game.component.html',
  styleUrls: ['./game.component.css']
})
export class GameComponent implements OnInit {

  game:Game;

  constructor(private gameService: GameService, private router: Router, private socketService: SocketService, private route: ActivatedRoute ) {
    this.game = this.route.snapshot.data['game']
  }
}

Is there something I'm not understanding about the hierarchy of angular dependency injection? I need the GameService to be a singleton service across all parts of the app, so I need the singleton instance to be injected in the Game Resolver Service without creating a new instance.

Ma7erick
  • 91
  • 10
  • Possible duplicate of [How do I create a singleton service in Angular 2?](https://stackoverflow.com/questions/36198785/how-do-i-create-a-singleton-service-in-angular-2) – Igor Jan 28 '19 at 22:15
  • 2
    You should either have `providedIn: 'root'` in the services themselves or add them as part of the `providers` array in the module, not both. – Dzhavat Ushev Jan 28 '19 at 22:27
  • @DzhavatUshev Thanks for pointing that out to me. I am still getting multiple GameService instances when implementing either choice however. – Ma7erick Jan 28 '19 at 22:42
  • What do you mean by multiple instances? Try injecting the `GameService` into another service and/or component and see whether the `constructor` runs? – Dzhavat Ushev Jan 28 '19 at 22:49
  • What I mean is that when GameService is injected into a Component, the GameService constructor is NOT called. But when it is injected into the GameResolverService, the GameService constructor is called. – Ma7erick Jan 28 '19 at 22:57
  • I created this quick example on StackBlitz (https://stackblitz.com/edit/angular-mmkds8). As you can see, I inject `GameService` in another service and the resolver but it's still singleton (by looking at the console logs) – Dzhavat Ushev Jan 28 '19 at 22:58
  • It is called. The constructor is not called. Calling the construction would mean creating another instance. The first inject will create the instance. Any other subsequent injection of that service will simply return the already created instance. – Dzhavat Ushev Jan 28 '19 at 23:00
  • Thank you for your example @DzhavatUshev. I can see its working there. When I inject my GameService into another service that is not a resolver, the GameService constructor is not called. Maybe my problem has to do with how I implemented the resolver? I'll try to update my code that I posted. – Ma7erick Jan 29 '19 at 00:15
  • Are you using lazy loaded modules? and please update the question to show how you're declaring the GameService. – Reactgular Jan 29 '19 at 02:02
  • @Ma7erick It's working for you as well. It doesn't matter where you inject the GameService (in a resolver, component or another service). When the code runs, it will instantiate the GameService the first time it encounters it (whether that's in the resolver, a component or another service). Injecting GameService from then on returns the same instance (meaning it's a singleton). – Dzhavat Ushev Jan 29 '19 at 08:16
  • @cgTag I am not using lazy loaded modules. When you say declaring the GameService, do you mean show where they are being declared in the constructors of the components that are using the GameSerivce? I will update my code the best I can to show GameService declarations. – Ma7erick Jan 29 '19 at 21:31

1 Answers1

3

I finally realized after much searching that in my app.component.ts file, I still had the providers array defined in the @Component decorator, while I was using the providedIn: 'root' method. Dzhavat Ushev was right, you cannot use both of these at the same time. I thought I had gotten rid of all my providers declarations, but I had no idea that one was there. It works perfectly now. Thanks for you help guys.

Ma7erick
  • 91
  • 10