Кутовий немає провайдера для NameService


326

У мене проблема з завантаженням класу в кутовий компонент. Я давно намагався вирішити це; Я навіть намагався об'єднати це все в одному файлі. Що у мене є:

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);

послуги / NameService.ts

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

Я постійно отримую повідомлення про помилку приказки No provider for NameService.

Чи може хтось допомогти мені визначити проблему з моїм кодом?


6
станом на Альфа 42: @Component ({провайдери: [NameService]})
timmz

Відповіді:


470

Ви повинні використовувати providersзамістьinjectables

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

Повний зразок коду тут .


7
@unobf заяви про імпорт не виглядають зламаними для мене. Попередня відповідь цілком може бути правильною для старих альфа-бібліотек angular2. Оригінальний посібник стосується альфа-28, я використовую альфа 35. Також я надаю посилання на повний зразок коду, тому я думаю, що я надав досить багато інформації.
Клас Меллбурн

4
Оновлення для майбутніх googlers: використання providersробіт над останньою бета-версією (бета-версія 0).
nathanhleung

@nathanhleung і прив'язки, і провайдери працюють - це тимчасово чи вони просто роблять те ж саме всередині
Simon_Weaver

@Simon_Weaver Хм, вони, можливо, змінили його в останній бета-версії - в бета.0. Я не зміг з цим працюватиbindings
nathanhleung

1
що робити, якщо послуга використовується з іншої послуги? я додав його до постачальників модулів, які, на мою думку, зробить його доступним у всьому світі, але все ж отримую цю помилку
Sonic Soul

79

У Angular 2 є три місця, за якими можна надати послуги:

  1. завантажувач
  2. кореневий компонент
  3. інші компоненти або директиви

"Опція постачальника завантажувальних програм призначена для налаштування та зміни власних попередньо зареєстрованих служб Angular, таких як його підтримка маршрутизації." - довідка

Якщо ви хочете лише один екземпляр NameService у всьому своєму додатку (тобто Singleton), додайте його до providersмасиву вашого кореневого компонента:

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

Plunker

Якщо ви хочете мати один екземпляр на компонент, використовуйте providersмасив в об'єкті конфігурації компонента:

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

Докладнішу інформацію див. У документі " Ієрархічні інжектори" .


4
Це дійсно гарна відповідь. Далі він пояснює відмінності між декларуванням служби в кореневому компоненті та декларуванням в інших дочірніх компонентах.
Таф

34

Станом на кутову 2 бета:

Додати @Injectableдо своєї служби як:

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

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

    getNames() {
        return this.names;
    }
}

і до конфігурації компонента додайте providers:

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

22

Ви повинні бути ін'єкційні NameServiceвсередині providersмасиву вашої AppModule«s NgModuleметаданих.

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

}

Якщо ви хочете створити залежність для певного рівня компонента, не турбуючись про стан вашої програми, ви можете ввести цю залежність від providersпараметра метаданих компонентів, як показаний прийнятий @Klass відповідь.


Я спробував додати службу в app.module.shared.ts у розділі @NgModule: провайдери: [DataManagerService], але все ж отримую помилку: Помилка: Немає провайдера для DataManagerService!
Пол

1
@Paul Ви ввели свою послугу в правильний Модуль? і чи DataManagerServiceє @Injectableдекоратор над ним?
Pankaj Parkar

15

Шокуюче, що синтаксис ще раз змінився в останній версії Angular :-) Від Angular 6 dokcs :

Починаючи з Angular 6.0, кращим способом створення одиночних служб є вказівка ​​на сервісі, яку вона повинна надавати в корені програми. Це робиться шляхом встановлення наданого корінця на корінь на @Injectable декоратор служби:

src / app / user.service.0.ts

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

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

14

Ви повинні ввести NameService всередині масиву постачальників метаданих NgModule вашого AppModule.

@NgModule({
   providers: [MyService]
})

і переконайтеся, що імпортуйте ваш компонент з тим самим іменем (з урахуванням регістру), оскільки SystemJs залежить від регістру (за дизайном). Якщо ви використовуєте інше ім’я шляху у файлах проекту, як це:

main.module.ts

import { MyService } from './MyService';

your-компонент.ts

import { MyService } from './Myservice';

тоді System js зробить подвійний імпорт


1
Відмінно! Під час використання бочок для групового імпорту я зіткнувся з цією помилкою. Ваш рада SystemJS допоміг мені :)
Jony Adamit


7

Кутовий 2 змінився, ось як має виглядати верх коду:

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

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

Крім того, ви можете скористатися геттерами та сетерами у вашій службі:

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

Тоді у своєму додатку ви можете просто зробити:

this.names = nameService.names;

Я пропоную вам зайти на plnkr.co і створити новий плагін Angular 2 (ES6) і спочатку змусити його працювати там. Це все налаштує на вас. Як тільки він працює там, скопіюйте його в інше середовище і попросіть будь-які проблеми з цим середовищем.


6

Помилка No provider for NameService є поширеною проблемою, з якою стикаються багато початківців Angular2.

Причина : Перш ніж скористатися будь-якою спеціальною службою, спочатку потрібно зареєструвати її в NgModule, додавши її до списку постачальників:

Рішення:

@NgModule({
    imports: [...],
    providers: [CustomServiceName]
})


4

Привіт, Ви можете використовувати це у своєму файлі .ts:

спочатку імпортуйте свою послугу у цей .ts файл:

import { Your_Service_Name } from './path_To_Your_Service_Name';

Потім у той самий файл ви можете додати providers: [Your_Service_Name]:

 @Component({
      selector: 'my-app',
      providers: [Your_Service_Name],
      template: `
        <h1>Hello World</h1> `   
    })


3

У Angular ви можете зареєструвати послугу двома способами:

1. Зареєструйте послугу в модулі або кореневому компоненті

Ефекти:

  • Доступний для всіх компонентів
  • Доступний у довічному застосуванні

Ви повинні подбати, якщо ви зареєструєте послугу в ледачому завантаженому модулі:

  • Послуга доступна лише для компонентів, оголошених у цьому модулі

  • Послуга буде доступна в застосуванні протягом усього життя лише тоді, коли модуль завантажений

2. Зареєструйте послугу в будь-якому іншому додатку

Ефекти:

  • До компонента буде введено окремий екземпляр Служби

Ви повинні подбати, якщо ви зареєструєте послугу в будь-якому іншому компоненті програми

  • Екземпляр введеної служби буде доступний лише для компонента та всіх його дітей.

  • Екземпляр буде доступний протягом життя компонента.


2

Вам потрібно додати його до масиву постачальників, який включає всю залежність вашого компонента.

Подивіться на цей розділ у кутовій документації:

Реєстрація постачальників у складі

Ось переглянений HeroesComponent, який реєструє HeroService у масиві своїх постачальників.

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 { }

Коли використовувати NgModule проти компонента програми

З одного боку, постачальник NgModule реєструється в кореневому інжекторі. Це означає, що кожен постачальник, зареєстрований у NgModule, буде доступний у всій програмі.

З іншого боку, постачальник, зареєстрований у компоненті програми, доступний лише для цього компонента та всіх його дітей.

Тут сервіс APP_CONFIG повинен бути доступний у всій програмі, тому він зареєстрований у масиві постачальників AppModule @NgModule. Але оскільки HeroService використовується лише в межах функції Heroes і ніде більше, є сенс зареєструвати його в HeroesComponent.

Також див. "Чи слід додати провайдерів для додатків до кореневого AppModule або кореневого AppComponent?" у поширених запитаннях про NgModule.

Тож у вашому випадку просто поміняйте ін’єкційні засоби на таких постачальників:

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

Також у нових версіях Angular, @View та деяких інших наповненнях немає.

Для отримання додаткової інформації відвідайте тут .


2

додати свою послугу до масиву провайдерів [] у файл app.module.ts. Як і нижче

// тут моя послуга CarService

app.module.ts

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

providers: [CarsService] // you can include as many services you have 

1

Angular2 вимагає оголосити всі ін'єкційні елементи у виклику функції завантаження. Без цього ваша послуга не є об'єктом для ін'єкцій.

bootstrap(MyAppComponent,[NameService]);

1
Це не зовсім правильно. Ми можемо включити службу в bootstrap () або до providersмасиву в об'єкт конфігурації компонента. Якщо він включений в providersмасив, ми отримуємо один екземпляр на зв'язаний компонент. Докладнішу інформацію див. У документі " Ієрархічні інжектори" .
Марк Райкок

так, як сказав @MarkRajcok, ми також надаємо лише ті послуги на момент завантаження, якими ми повинні користуватися протягом усього додатка. тим самим нам не потрібно було вводити кожен раз провайдера, оскільки це створить екземпляр для кожного компонента.
Pardeep Jain

1

Додайте @Injectable до вашої послуги як:

export class NameService {
    names: Array<string>;

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

    getNames() {
        return this.names;
    }
}

і у своєму компоненті додайте провайдерів у вигляді:

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

або якщо ви хочете отримати доступ до своєї послуги у всій програмі, ви можете передати її у постачальника програм


1

Блок-котирування

Реєстрація постачальників у складі

Ось переглянений HeroesComponent, який реєструє HeroService у масиві своїх постачальників.

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

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

@Component({
  selector: 'my-heroes',
  providers: [HeroService],
  template: `
  `
})
export class HeroesComponent { }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.