2016-07-05 14 views
7

Tôi có câu hỏi DI Angular2. Giả sử tôi có số TestService và tôi muốn sử dụng 2 phiên bản dịch vụ khác trong cùng một thành phần. Nếu tôi chỉ đơn giản là thêm một nhà cung cấp vào thành phần và tôi thêm 2 trường hợp vào hàm tạo, tôi kết thúc với cùng một cá thể dịch vụ. Ví dụ:Angular2 DI - khởi tạo nhiều phiên bản khác nhau trong cùng một hàm tạo

TestService

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

@Injectable() 
export class TestService { 

    public id: number = Math.random(); 

    public toString(): string { 
     return "Id: " + this.id; 
    } 
} 

Kiểm tra thành phần

import {Component, Input, OnInit} from "@angular/core"; 
import {TestService} from "../../services/test.service"; 

@Component({ 
    providers: [TestService] 
}) 
export class TestComponent implements OnInit { 

    constructor(private _testService1: TestService, private _testService2: TestService) { }; 

    ngOnInit() { 
     console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", this._testService1.toString()); 
     console.log("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", this._testService2.toString()); 
    } 
} 

quả trong giao diện điều khiển

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Id: 0.24242492129168425 
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB Id: 0.24242492129168425 

Ai đó có thể cho tôi biết nếu có cách nào để sử dụng cơ chế DI của Angular2 để tiêm nhiều trường hợp khác nhau của một dịch vụ trong cùng một thành phần hoặc tôi chỉ cần thả DI cho trường hợp cụ thể này và tạo các cá thể của tôi theo cách thủ công với một hàm tạo thủ công?

Cảm ơn trước

Trả lời

3

Bạn có thể tiêm một nhà máy mà trả về một trường hợp mới mỗi khi bạn gọi nó là:

@NgModule({ 
    providers: [{ 
     provide: 'testService', 
     useFactory: (/* TestService deps here like `http`*/) => 
     (/* params */) => new TestService(/* http */), 
     deps: [/* TestService deps here like `Http`*/ ] 
    }] 
}) 


@Component(...) 
export class TestComponent implements OnInit { 

    constructor(@Inject('testService') private _testServiceFactory) { }; 

    ngOnInit() { 
     console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", this._testServiceFactory(/* params */).toString()); 
     console.log("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", this._testServiceFactory().toString()); 
    } 
} 

Plunker example (kiểm tra đầu ra trong trình duyệt giao diện điều khiển khi bạn nhấp vào nút)

+0

Sẽ thú vị những gì downvote là cho. –

+2

Nó chỉ đơn giản là không làm công việc. Nếu bạn tiêm với useFactory, nhà máy sẽ chỉ được sử dụng một lần để tiêm vào _testServiceFactory. Nhưng đoạn mã này sẽ không hoạt động được, vì bạn không có kiểu cho đối số hàm tạo, góc cạnh không thể biết cái gì cần tiêm. –

+1

@TimKachko cảm ơn rất nhiều vì phản hồi quý giá của bạn! Tôi đã cập nhật câu trả lời của mình. Bạn nói đúng, về loại. Tôi đã thay đổi nó để sử dụng một khóa chuỗi thay vì với '@Inject()'. Nhà máy sẽ hoạt động. Có lẽ tôi có thể làm cho nó rõ ràng hơn trong mã, nhưng nhà máy là một hàm trả về một hàm, do đó DI sẽ giữ một thể hiện của hàm trả về và chuyển nó cho mỗi lớp mà tiêm ''testService'' và bởi vì một hàm được truyền cho hàm tạo trả về một 'new TestService()' mỗi khi nó được gọi, điều này sẽ làm việc. –

2

tôi sẽ tạo ra một phương pháp tĩnh trả về ví dụ mới trong dịch vụ, và tiêm nó chỉ có một qua DI trong thành phần. Một cái gì đó như:

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

@Injectable() 
export class TestService { 

    public id: number = Math.random(); 

    public toString(): string { 
     return "Id: " + this.id; 
    } 
    static init() { 
     return new TestService(); 
    } 
} 

sau đó trong thành phần:

import {Component, Input, OnInit} from "@angular/core"; 
import {TestService} from "../../services/test.service"; 

@Component({ 
    providers: [TestService] 
}) 
export class TestComponent implements OnInit { 
    _testService1: TestService; 
    _testService2: TestService; 

    constructor(_testFactory: TestService) { 
     this._testService1 = _testFactory.init(); 
     this._testService2 = _testFactory.init(); 
    }; 

    ngOnInit() { 
     console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", this._testService1.toString()); 
     console.log("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", this._testService2.toString()); 
    } 
} 
+0

này cũng phù hợp với kiểu mã hóa từ tài liệu của nhóm 2 của Angular. – BrianRT

+0

Điều là nơi bạn lưu trữ hai trường hợp này trong trường hợp các thành phần khác cần chúng. –

10

Cho rằng có số lượng hữu hạn các trường hợp, cách đơn giản có thể là:

@Component({ 
    providers: [ 
     { provide: 'TestService1', useClass: TestService }, 
     { provide: 'TestService2', useClass: TestService } 
    ] 
}) 
export class TestComponent implements OnInit { 
    constructor(
     @Inject('TestService1') private _testService1: TestService, 
     @Inject('TestService2') private _testService2: TestService 
    ) {} 
    ... 
} 

Hoặc OpaqueToken đối tác để tránh các dịch vụ trọng có cùng số nhận dạng chuỗi:

export const TestService1 = new OpaqueToken; 
export const TestService2 = new OpaqueToken; 

... 
providers: [ 
    { provide: TestService1, useClass: TestService }, 
    { provide: TestService2, useClass: TestService } 
] 
... 
constructor(
    @Inject(TestService1) private _testService1: TestService, 
    @Inject(TestService2) private _testService2: TestService 
) {} 

Nó không làm tổn thương DI trong số TestService hàm tạo. Và giữ cho testability của TestComponent ngang, cả hai trường hợp dịch vụ có thể được giả lập một cách độc lập.

+2

Câu trả lời hay. Để hoàn thành, tôi sẽ nói OpaqueToken cũng nên được sử dụng thay vì các chuỗi để tránh va chạm đặt tên: https://angular.io/docs/ts/latest/api/core/index/OpaqueToken-class.html –

+0

@CharlesHETIER Cảm ơn, chuỗi định danh được sử dụng ở đây cho ngắn gọn, nhưng nó không làm tổn thương đề cập đến rằng OpaqueToken có thể được sử dụng là tốt. – estus

Các vấn đề liên quan