Angular không có nhà cung cấp cho NameService


325

Tôi đã gặp sự cố khi tải một lớp vào thành phần Angular. Tôi đã cố gắng giải quyết nó trong một thời gian dài; Tôi thậm chí đã thử tham gia tất cả trong một tệp duy nhất. Những gì tôi có là:

Ứng dụng

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

dịch vụ / NameService.ts

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

Tôi tiếp tục nhận được một thông báo lỗi nói No provider for NameService.

Ai đó có thể giúp tôi phát hiện vấn đề với mã của tôi không?


6
kể từ Alpha 42: @Component ({nhà cung cấp: [NameService]})
timmz

Câu trả lời:


470

Bạn phải sử dụng providersthay vìinjectables

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

Hoàn thành mẫu mã ở đây .


7
@unobf báo cáo nhập khẩu không bị hỏng đối với tôi. Câu trả lời trước đó cũng có thể đúng cho các bảng chữ cái cũ của thư viện angular2. Hướng dẫn ban đầu đề cập đến alpha-28, tôi sử dụng alpha 35. Ngoài ra, tôi cung cấp một liên kết đến một mẫu mã hoàn chỉnh, vì vậy tôi nghĩ rằng tôi đã cung cấp khá nhiều thông tin.
Klas Mellbourn

4
Một bản cập nhật cho các nhân viên của Google trong tương lai: sử dụng providerscác tác phẩm trên phiên bản beta mới nhất (beta 0).
nathanhleung

@nathanhleung cả hai ràng buộc và nhà cung cấp đều hoạt động - đây là tạm thời hoặc chúng chỉ hoạt động giống nhau trong nội bộ
Simon_Weaver

@Simon_Weaver hmm họ có thể đã thay đổi nó trong bản beta mới nhất - trong phiên bản beta.0 tôi không thể làm cho nó hoạt động vớibindings
nathanhleung

1
Nếu dịch vụ được sử dụng từ dịch vụ khác thì sao? tôi đã thêm nó vào các nhà cung cấp mô-đun mà tôi nghĩ sẽ cung cấp nó trên toàn cầu, nhưng vẫn gặp phải lỗi đó
Sonic Soul

79

Trong Angular 2 có ba nơi bạn có thể "cung cấp" dịch vụ:

  1. bootstrap
  2. thành phần gốc
  3. các thành phần hoặc chỉ thị khác

"Tùy chọn nhà cung cấp bootstrap được thiết kế để định cấu hình và ghi đè các dịch vụ được đăng ký trước của Angular, chẳng hạn như hỗ trợ định tuyến của nó." - tham khảo

Nếu bạn chỉ muốn một phiên bản của NameService trên toàn bộ ứng dụng của mình (ví dụ: Singleton), thì hãy đưa nó vào providersmảng thành phần gốc của bạn:

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

Plunker

Nếu bạn muốn có một phiên bản cho mỗi thành phần, hãy sử dụng providersmảng trong đối tượng cấu hình của thành phần thay thế:

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

Xem tài liệu In phun phân cấp để biết thêm thông tin.


4
Đây là một câu trả lời thực sự tốt. Nó giải thích thêm về sự khác biệt giữa khai báo dịch vụ trong thành phần gốc so với khai báo trong các thành phần con khác.
Taf

33

Kể từ phiên bản Angular 2 Beta:

Thêm @Injectablevào dịch vụ của bạn dưới dạng:

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

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

    getNames() {
        return this.names;
    }
}

và để cấu hình thành phần của bạn thêm vào providersnhư:

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

22

Bạn nên tiêm NameServicebên trong providersmảng của bạn AppModule's NgModulesiêu dữ liệu.

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

}

Nếu bạn muốn tạo Phụ thuộc cho cấp thành phần cụ thể mà không bận tâm về trạng thái ứng dụng của mình, thì bạn có thể đưa tùy thuộc đó vào providerstùy chọn siêu dữ liệu thành phần như câu trả lời @Klass được chấp nhận hiển thị.


Tôi đã thử thêm một dịch vụ trong app.module. Shared.ts trong phần @NgModule: nhà cung cấp: [DataManagerService] nhưng vẫn gặp lỗi: Lỗi: Không có nhà cung cấp cho DataManagerService!
Paul

1
@Paul bạn đang tiêm dịch vụ của mình vào Module chính xác phải không? và DataManagerService@Injectabletrang trí trên nó?
Pankaj Parkar

15

Thật đáng kinh ngạc, cú pháp đã thay đổi một lần nữa trong phiên bản mới nhất của Angular :-) Từ các tài liệu Angular 6 :

Bắt đầu với Angular 6.0, cách ưa thích để tạo một dịch vụ đơn lẻ là chỉ định dịch vụ cần được cung cấp trong thư mục gốc. Điều này được thực hiện bằng cách cài đặt được cung cấp để root trên trang trí @Injectable của dịch vụ:

src / ứng dụng / user.service.0.ts

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

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

14

Bạn nên tiêm NameService bên trong mảng nhà cung cấp của siêu dữ liệu NgModule của AppModule.

@NgModule({
   providers: [MyService]
})

và chắc chắn nhập vào thành phần của bạn cùng tên (phân biệt chữ hoa chữ thường), bởi vì SystemJs phân biệt chữ hoa chữ thường (theo thiết kế). Nếu bạn sử dụng tên đường dẫn khác nhau trong các tệp dự án của bạn như thế này:

main.module.ts

import { MyService } from './MyService';

thành phần của bạn

import { MyService } from './Myservice';

sau đó hệ thống js sẽ thực hiện nhập khẩu gấp đôi


1
Thông minh! Khi sử dụng thùng để nhập nhóm tôi gặp phải lỗi này. Mẹo SystemJS của bạn đã giúp tôi :)
Jony Adamit

12

Trong Angular v2 trở lên, bây giờ:

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


7

Angular 2 đã thay đổi, đây là phần trên cùng của mã của bạn sẽ trông như thế nào:

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

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

Ngoài ra, bạn có thể muốn sử dụng getters và setters trong dịch vụ của mình:

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

Sau đó, trong ứng dụng của bạn, bạn có thể chỉ cần làm:

this.names = nameService.names;

Tôi khuyên bạn nên truy cập plnkr.co và tạo một plunk Angular 2 (ES6) mới và làm cho nó hoạt động ở đó trước. Nó sẽ thiết lập mọi thứ cho bạn. Khi nó hoạt động ở đó, hãy sao chép nó sang môi trường khác của bạn và xử lý mọi vấn đề với môi trường đó.


6

Lỗi No provider for NameServicelà một vấn đề phổ biến mà nhiều người mới bắt đầu Angular2 phải đối mặt.

Lý do : Trước khi sử dụng bất kỳ dịch vụ tùy chỉnh nào, trước tiên bạn phải đăng ký dịch vụ này với NgModule bằng cách thêm nó vào danh sách nhà cung cấp:

Giải pháp:

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


4

Xin chào, Bạn có thể sử dụng tệp này trong tệp .ts của mình:

đầu tiên nhập dịch vụ của bạn trong tệp .ts này:

import { Your_Service_Name } from './path_To_Your_Service_Name';

Sau đó, trong cùng một tệp bạn có thể thêm providers: [Your_Service_Name]:

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

4

Thêm nó vào nhà cung cấp không tiêm

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

3

Trong Angular bạn có thể đăng ký một dịch vụ theo hai cách:

1. Đăng ký một dịch vụ trong mô-đun hoặc thành phần gốc

Các hiệu ứng:

  • Có sẵn trong tất cả các thành phần
  • Có sẵn trên ứng dụng trọn đời

Bạn nên cẩn thận nếu bạn đăng ký một dịch vụ vào một mô-đun tải lười biếng:

  • Dịch vụ chỉ có sẵn trong các thành phần được khai báo trong mô-đun đó

  • Dịch vụ sẽ chỉ khả dụng trên ứng dụng trọn đời khi mô-đun được tải

2. Đăng ký một dịch vụ vào bất kỳ thành phần ứng dụng nào khác

Các hiệu ứng:

  • Sẽ được tiêm một phiên bản riêng của Dịch vụ vào thành phần

Bạn nên cẩn thận nếu bạn đăng ký một dịch vụ vào bất kỳ thành phần ứng dụng nào khác

  • Thể hiện của dịch vụ được tiêm sẽ chỉ có sẵn trong thành phần và tất cả các phần tử con của nó.

  • Ví dụ sẽ có sẵn trên vòng đời thành phần.


2

Bạn cần thêm nó vào mảng nhà cung cấp, bao gồm tất cả các phụ thuộc vào thành phần của bạn.

Nhìn vào phần này trong tài liệu góc:

Đăng ký nhà cung cấp trong một thành phần

Đây là một HeroesComponent được sửa đổi, đăng ký HeroService trong mảng nhà cung cấp của nó.

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

Khi nào nên sử dụng NgModule so với thành phần ứng dụng

Một mặt, một nhà cung cấp trong NgModule được đăng ký trong bộ tiêm gốc. Điều đó có nghĩa là mọi nhà cung cấp đã đăng ký trong NgModule sẽ có thể truy cập được trong toàn bộ ứng dụng.

Mặt khác, một nhà cung cấp đã đăng ký trong một thành phần ứng dụng chỉ có sẵn trên thành phần đó và tất cả các phần tử con của nó.

Tại đây, dịch vụ APP_CONFIG cần phải có sẵn trên tất cả các ứng dụng, do đó, dịch vụ này đã được đăng ký trong mảng nhà cung cấp AppModule @NgModule. Nhưng vì HeroService chỉ được sử dụng trong khu vực tính năng Heroes và không ở đâu khác, nên đăng ký nó trong HeroesComponent là điều hợp lý.

Đồng thời xem "Tôi nên thêm nhà cung cấp toàn ứng dụng vào AppModule gốc hoặc AppComponent gốc?" trong Câu hỏi thường gặp về NgModule.

Vì vậy, trong trường hợp của bạn, chỉ cần thay đổi thuốc tiêm cho các nhà cung cấp như dưới đây:

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

Ngoài ra trong các phiên bản mới của Angular, @View và một số thứ khác đã biến mất.

Để biết thêm thông tin, hãy truy cập vào đây .


2

thêm dịch vụ của bạn vào mảng nhà cung cấp [] trong tệp app.module.ts. Thích bên dưới

// ở đây dịch vụ của tôi là CarService

app.module.ts

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

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

1

Angular2 yêu cầu bạn khai báo tất cả các mũi tiêm trong lệnh gọi hàm bootstrap. Không có điều này, dịch vụ của bạn không phải là một đối tượng tiêm.

bootstrap(MyAppComponent,[NameService]);

1
Điều này không hoàn toàn chính xác. Chúng ta có thể bao gồm dịch vụ trong bootstrap () hoặc trong providersmảng trong đối tượng cấu hình của thành phần. Nếu nó được bao gồm trong providersmảng, chúng ta sẽ nhận được một thể hiện cho mỗi thành phần bị ràng buộc. Xem tài liệu In phun phân cấp để biết thêm thông tin.
Mark Rajcok

vâng, như đã nói bởi @MarkRajcok, chúng tôi cũng chỉ cung cấp các dịch vụ đó tại thời điểm bootstrap mà chúng tôi phải sử dụng trong toàn bộ ứng dụng. bằng cách đó, chúng tôi không cần tiêm mỗi lần vào nhà cung cấp vì nó sẽ tạo ra thể hiện cho mọi thành phần.
Pardeep Jain

1

Thêm @Injectable vào dịch vụ của bạn dưới dạng:

export class NameService {
    names: Array<string>;

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

    getNames() {
        return this.names;
    }
}

và trong thành phần của bạn thêm các nhà cung cấp như:

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

hoặc nếu bạn muốn truy cập dịch vụ của mình trên tất cả các ứng dụng, bạn có thể vượt qua nhà cung cấp ứng dụng


1

Blockquote

Đăng ký nhà cung cấp trong một thành phần

Đây là một HeroesComponent được sửa đổi, đăng ký HeroService trong mảng nhà cung cấp của nó.

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

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

@Component({
  selector: 'my-heroes',
  providers: [HeroService],
  template: `
  `
})
export class HeroesComponent { }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.