384

I've got a problem loading a class into an Angular component. I've been trying to solve it for a long time; I've even tried joining it all in a single file. What I have is:

Application.ts

/// <reference path="../typings/angular2/angular2.d.ts" />

import {Component,View,bootstrap,NgFor} from "angular2/angular2";
import {NameService} from "./services/NameService";

@Component({
    selector:'my-app',
    injectables: [NameService]
})
@View({
    template:'<h1>Hi {{name}}</h1>' +
    '<p>Friends</p>' +
    '<ul>' +
    '   <li *ng-for="#name of names">{{name}}</li>' +
    '</ul>',
    directives:[NgFor]
})

class MyAppComponent
{
    name:string;
    names:Array<string>;

    constructor(nameService:NameService)
    {
        this.name = 'Michal';
        this.names = nameService.getNames();
    }
}
bootstrap(MyAppComponent);

services/NameService.ts

export class NameService {
    names: Array<string>;
    constructor() {
        this.names = ["Alice", "Aarav", "Martín", "Shannon", "Ariana", "Kai"];
    }
    getNames()
    {
        return this.names;
    }
}

I keep getting an error message saying No provider for NameService.

Can someone help me spot the issue with my code?

Sofia Paixão
  • 309
  • 2
  • 16
M.Svrcek
  • 5,485
  • 4
  • 25
  • 33

18 Answers18

531

You have to use providers instead of injectables

@Component({
    selector: 'my-app',
    providers: [NameService]
})

Complete code sample here.

Klas Mellbourn
  • 42,571
  • 24
  • 140
  • 158
83

In Angular 2 there are three places you can "provide" services:

  1. bootstrap
  2. root component
  3. other components or directives

"The bootstrap provider option is intended for configuring and overriding Angular's own preregistered services, such as its routing support." -- reference

If you only want one instance of NameService across your entire app (i.e., Singleton), then include it in the providers array of your root component:

@Component({
   providers: [NameService],
   ...
)}
export class AppComponent { ... }

Plunker

If you would rather have one instance per component, use the providers array in the component's configuration object instead:

@Component({
   providers: [NameService],
   ...
)}
export class SomeOtherComponentOrDirective { ... }

See the Hierarchical Injectors doc for more info.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 4
    This is a really good answer. It further explains the differences between declaring the service in the root component versus declaring in other child components. – Taf Feb 07 '17 at 22:51
36

As of Angular 2 Beta:

Add @Injectable to your service as:

@Injectable()
export class NameService {
    names: Array<string>;

    constructor() {
        this.names = ["Alice", "Aarav", "Martín", "Shannon", "Ariana", "Kai"];
    }

    getNames() {
        return this.names;
    }
}

and to your component config add the providers as:

@Component({
    selector: 'my-app',
    providers: [NameService]
})
magiccrafter
  • 5,175
  • 1
  • 56
  • 50
25

You should be injecting NameService inside providers array of your AppModule's NgModule metadata.

@NgModule({
   imports: [BrowserModule, ...],
   declarations: [...],
   bootstrap: [AppComponent],
   //inject providers below if you want single instance to be share amongst app
   providers: [MyService]
})
export class AppModule {

}

If you want to create an Dependency for particular component level without bothering about state of your application, then you can inject that dependency on component providers metadata option like accepted @Klass answer shown.

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • I have tried adding a service in app.module.shared.ts in @NgModule section : providers: [DataManagerService] but still get the error : Error: No provider for DataManagerService! – Paul Oct 17 '17 at 16:09
  • 1
    @Paul are you injecting your service in correct Module? and does `DataManagerService` has `@Injectable` decorator over it? – Pankaj Parkar Oct 17 '17 at 16:47
22

Shockingly, the syntax has changed yet again in the latest version of Angular :-) From the Angular 6 docs:

Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root. This is done by setting providedIn to root on the service's @Injectable decorator:

src/app/user.service.0.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class UserService {
}
Derrick Miller
  • 1,860
  • 3
  • 21
  • 37
15

You should be injecting NameService inside providers array of your AppModule's NgModule metadata.

@NgModule({
   providers: [MyService]
})

and be sure import in your component by same name (case sensitive),becouse SystemJs is case sensitive (by design). If you use different path name in your project files like this:

main.module.ts

import { MyService } from './MyService';

your-component.ts

import { MyService } from './Myservice';

then System js will make double imports

saghar.fadaei
  • 3,205
  • 1
  • 17
  • 10
13

In Angular v2 and up it is now:

@Component({ selector:'my-app', providers: [NameService], template: ... })

supercobra
  • 15,810
  • 9
  • 45
  • 51
7

Angular 2 has changed, here is what the top of your code should look like:

import {
  ComponentAnnotation as Component,
  ViewAnnotation as View, bootstrap
} from 'angular2/angular2';
import {NameService} from "./services/NameService";

@Component({
  selector: 'app',
  appInjector: [NameService]
})

Also, you may want to use getters and setters in your service:

export class NameService {
    _names: Array<string>;
    constructor() {
        this._names = ["Alice", "Aarav", "Martín", "Shannon", "Ariana", "Kai"];
    }
    get names() {
        return this._names;
    }
}

Then in your app you can simply do:

this.names = nameService.names;

I suggest you go to plnkr.co and create a new Angular 2 (ES6) plunk and get it to work in there first. It will set everything up for you. Once it's working there, copy it over to your other environment and triage any issues with that environment.

unobf
  • 7,158
  • 1
  • 23
  • 36
7

The error No provider for NameService is a common issue that many Angular2 beginners face.

Reason: Before using any custom service you first have to register it with NgModule by adding it to the providers list:

Solution:

@NgModule({
    imports: [...],
    providers: [CustomServiceName]
})
trixn
  • 15,761
  • 2
  • 38
  • 55
Suneet Bansal
  • 2,664
  • 1
  • 14
  • 18
5

You could also have the dependencies declared in the bootstrap-command like:

bootstrap(MyAppComponent,[NameService]);

At least that's what worked for me in alpha40.

this is the link: http://www.syntaxsuccess.com/viewarticle/dependency-injection-in-angular-2.0

Tobias Gassmann
  • 11,399
  • 15
  • 58
  • 92
4

Hi , You can use this in your .ts file :

first import your service in this .ts file:

import { Your_Service_Name } from './path_To_Your_Service_Name';

Then in the same file you can add providers: [Your_Service_Name] :

 @Component({
      selector: 'my-app',
      providers: [Your_Service_Name],
      template: `
        <h1>Hello World</h1> `   
    })
Shubham Verma
  • 8,783
  • 6
  • 58
  • 79
4

Add it to providers not injectables

@Component({
    selector:'my-app',
    providers: [NameService]
})
Gopinath Kaliappan
  • 6,929
  • 8
  • 37
  • 60
4

In Angular you are able to register a service in two ways:

1. Register a service in module or root component

Effects:

  • Available into all components
  • Available on lifetime application

You should take care if you register a service into a lazy loaded module:

  • The service is available only into components declared into that module

  • The service will be available on lifetime application only when the module is loaded

2. Register a service into any other application component

Effects:

  • Will be injected a separate instance of the Service into the component

You should take care if you register a service into any other application component

  • The instance of the injected service will be available only into the component and all of its children.

  • The instance will be available on the component lifetime.

RazvanParautiu
  • 2,805
  • 2
  • 18
  • 21
3

add your service to providers[] array in app.module.ts file. Like below

// here my service is CarService

app.module.ts

import {CarsService} from './cars.service';

providers: [CarsService] // you can include as many services you have 
The Hungry Dictator
  • 3,444
  • 5
  • 37
  • 53
2

You need to add it to providers array, which includes all depency on your component.

Look at this section in angular documentation:

Registering providers in a component

Here's a revised HeroesComponent that registers the HeroService in its providers array.

import { Component } from '@angular/core';

import { HeroService } from './hero.service';

@Component({
  selector: 'my-heroes',
  providers: [HeroService],
  template: `
  <h2>Heroes</h2>
  <hero-list></hero-list>
  `
})
export class HeroesComponent { }

When to use NgModule versus an application component

On the one hand, a provider in an NgModule is registered in the root injector. That means that every provider registered within an NgModule will be accessible in the entire application.

On the other hand, a provider registered in an application component is available only on that component and all its children.

Here, the APP_CONFIG service needs to be available all across the application, so it's registered in the AppModule @NgModule providers array. But since the HeroService is only used within the Heroes feature area and nowhere else, it makes sense to register it in the HeroesComponent.

Also see "Should I add app-wide providers to the root AppModule or the root AppComponent?" in the NgModule FAQ.

So in your case, simply change injectables to providers like below:

@Component({
  selector: 'my-app',
  providers: [NameService]
})

Also in the new versions of Angular, @View and some other stuffs gone.

For more info ,visit here.

Alireza
  • 100,211
  • 27
  • 269
  • 172
2

Blockquote

Registering providers in a component

Here's a revised HeroesComponent that registers the HeroService in its providers array.

import { Component } from '@angular/core';

import { HeroService } from './hero.service';

@Component({
  selector: 'my-heroes',
  providers: [HeroService],
  template: `
  `
})
export class HeroesComponent { }
Chanaka Weerasinghe
  • 5,404
  • 2
  • 26
  • 39
1

Angular2 requires you to declare all the injectables in bootstrap function call. Without this your service is not an injectable object.

bootstrap(MyAppComponent,[NameService]);
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
preet0982
  • 51
  • 4
  • 1
    This is not quite correct. We can include the service in bootstrap(), or in the `providers` array in the component's configuration object. If it is included in the `providers` array, we get one instance per bound component. See the [Hierarchical Injectors](https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html) doc for more info. – Mark Rajcok Nov 14 '15 at 22:58
  • yes as said by @MarkRajcok also we provide only those services at the time of bootstrap which one's we have to use throughout the whole app. by doing so we did't need to inject every time in the provider because it will create instance for the every component. – Pardeep Jain Feb 01 '16 at 05:05
1

Add @Injectable to your service as:

export class NameService {
    names: Array<string>;

    constructor() {
        this.names = ["Alice", "Aarav", "Martín", "Shannon", "Ariana", "Kai"];
    }

    getNames() {
        return this.names;
    }
}

and in your component add the providers as:

@Component({
    selector: 'my-app',
    providers: [NameService]
})

or if you want to access your service all over the application you can pass in app provider

Rob
  • 26,989
  • 16
  • 82
  • 98