1

I'm trying to create an angular (beta7) app. At the top there should be a MenuComponent that uses the NavigationService to navigate to different parts of my app. I want the NavigationService to be singleton and therefore am instantiating it with bootstrap(...). I know you can also add providers in the @Component() but as far as I know that would mean that those providers are not singleton but instead created per instance.

However I'm getting the following exception:

No provider for NavigationService! (MenuComponent -> NavigationService)

Here is my code:

boot.ts

import {bootstrap} from 'angular2/platform/browser'
import {provide} from 'angular2/core'
import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router'
import {HubService} from './services/HubService';
import {ConfigService} from './services/ConfigService';
import {App} from './app';
import {NavigationService} from './services/NavigationService';

var bootstrap_application = function () {
    var providers = [
        ROUTER_PROVIDERS,
        NavigationService,
        HubService,
        ConfigService,
        provide(LocationStrategy, { useClass: HashLocationStrategy })];
    bootstrap(App, providers);
};

bootstrap_application();

app.ts

import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES, RouteConfig} from 'angular2/router'
import {MenuComponent} from './components/menu/menu';
import {HomeComponent} from './components/home/home';
import {RoomComponent} from './components/room/room';

@Component({
    selector: 'hc',
    templateUrl: 'app/app.html',
    directives: [ROUTER_DIRECTIVES, MenuComponent]
})
@RouteConfig([
    { path: "/", name: "Home", component: HomeComponent, useAsDefault: true },
    { path: "/room/:name", name: "Room", component: RoomComponent }
])
export class App {
}

app.html

<hc-menu>Loading menu...</hc-menu>
<div class="container-fluid">
    <router-outlet></router-outlet>
</div>

menu.ts

import {Component} from 'angular2/core';
import {Room, ConfigService} from '../../Services/ConfigService';
import {NavigationService} from '../../Services/NavigationService';

@Component({
    selector: 'hc-menu',
    templateUrl: 'app/components/menu/menu.html'
})
export class MenuComponent {
    Rooms: Room[];
    IsOpen: boolean;

    constructor(private navigationService: NavigationService, private configService: ConfigService) {
        this.Rooms = configService.GetRooms();
        this.IsOpen = false;
    }

    toggleOpen() {
        this.IsOpen = !this.IsOpen;
    }

    navigateTo(room: Room) {
        this.navigationService.navigateToRoom(room);
    }
}

NavigationService.ts

import {Injectable} from 'angular2/core';
import {Router} from 'angular2/router';
import {Room} from './ConfigService'

@Injectable()
export class NavigationService {
    router: Router;

    constructor(router: Router) {
        this.router = router;
    }

    navigateToRoom(room: Room) {
        this.router.navigate(['Room', { name: room.Name }]);
    }
}
wertzui
  • 5,148
  • 3
  • 31
  • 51

1 Answers1

0

In your MenuComponent Class add providers:[NavigationService] as a property of @Component.

@Component({
    selector: 'hc-menu',
    providers:[NavigationService],
    templateUrl: 'app/components/menu/menu.html'
})
Eric Martinez
  • 31,277
  • 9
  • 92
  • 91
Michael Desigaud
  • 2,115
  • 1
  • 15
  • 15
  • wouldn't `providers:[NavigationService]` will create new instance of `NavigationService`? – Pankaj Parkar Feb 28 '16 at 22:01
  • No it will be a singleton – Michael Desigaud Feb 28 '16 at 22:04
  • please do add explanation to answer.. how will it happen? that will be appreciated then. Thanks :) – Pankaj Parkar Feb 28 '16 at 22:05
  • The providers property doesn’t configure the instances that will be injected but it configures an injector that is created for a given component, for example NavigationService. Which allows you to autowire an instance of it in the constructor. – Michael Desigaud Feb 28 '16 at 22:17
  • I don't fully understand, could you elaborate more please.? – Pankaj Parkar Feb 28 '16 at 22:21
  • 1
    Sorry for the confusion. providers:[NavigationService] will internally configure an injector for the given component (annotated @Component, here MenuComponent). Its then possible to make a dependency injection on the specified types (NavigationService in that case). But providers do not make instanciation. – Michael Desigaud Feb 28 '16 at 22:35
  • In that case `MenuComponent` would have an own injector and not share one with the `App`. Wouldn't that mean that they both get different instances of the `NavigationService`? Here https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html at the bottom of the page it is written that we should be able to use `bootstrap(...)` to define the provider. – wertzui Feb 29 '16 at 07:11
  • i think `bootstrap` is to create injectors globally and the providers property of the @Component metadata is to create injector only for the current component (`MenuComponent`) – Michael Desigaud Feb 29 '16 at 12:56
  • In my boot.ts I added the `NavigationService` so shouldn't it be available to each component globally? – wertzui Feb 29 '16 at 17:25
  • `bootstrap(NavigationService)` creates an injector globally for the `NavigationService` type that allows you to make dependency injection anywhere (in the constructor for example). So if you do that you shouldn't have to use the providers property on your `@Component` for this type. – Michael Desigaud Feb 29 '16 at 17:34
  • The `MenuComponent` has a parameter of type `NavigationService` in its constructor, but it does not work. – wertzui Feb 29 '16 at 18:34
  • does it work if you add it to the `providers` property in the `@Component` metadata ? – Michael Desigaud Mar 01 '16 at 15:18