Угловой нет провайдера для 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
по состоянию на Alpha 42: @Component ({поставщики: [NameService]})
timmz

Ответы:


470

Вы должны использовать providersвместоinjectables

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

Полный пример кода здесь .


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

4
Обновление для будущих гуглов: использование 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 { ... }

См. Документ Hierarchical Injectors для получения дополнительной информации.


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

34

Начиная с Angular 2 Beta:

Добавьте @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
@ Пол, вы вводите свой сервис в правильном модуле? и DataManagerServiceимеет ли @Injectableдекоратор над ним?
Панкадж Паркар

15

Шокирующе, синтаксис снова изменился в последней версии Angular :-) Из документов Angular 6 :

Начиная с Angular 6.0, предпочтительным способом создания одноэлементных сервисов является указание для сервиса, что он должен быть предоставлен в корне приложения. Это можно сделать, установив предоставляемый параметр root в корне в декораторе @Injectable службы:

ЦСИ / приложение / 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';

ваш-component.ts

import { MyService } from './Myservice';

тогда система js сделает двойной импорт


1
Превосходно! При использовании стволов для группового импорта я столкнулся с этой ошибкой. Мне помог твой совет по SystemJS :)
Джони Адамит,

12

В Angular v2 и выше это сейчас:

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


7

Angular 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.

Также см. «Должен ли я добавить провайдеров всего приложения в корневой AppModule или корневой AppComponent?» в FAQ по NgModule.

Так что в вашем случае просто замените инъекционные препараты на поставщиков, как показано ниже:

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

Также в новых версиях Angular, @View и некоторых других вещей нет.

Для получения дополнительной информации посетите здесь .


2

добавьте свой сервис в массив provider [] в файле 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массив, мы получаем один экземпляр на связанный компонент. См. Документ Hierarchical Injectors для получения дополнительной информации.
Марк Райкок

да, как сказал @MarkRajcok, во время начальной загрузки мы также предоставляем только те услуги, которые мы должны использовать во всем приложении. при этом нам не нужно вводить каждый раз в провайдере, потому что он создаст экземпляр для каждого компонента.
Пардип Джейн

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

Blockquote

Регистрация провайдеров в компоненте

Вот пересмотренный 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.