2016-07-05 25 views
7

Ho una domanda DI Angular2. Supponiamo di avere un TestService e voglio utilizzare 2 diverse istanze di questo servizio all'interno dello stesso componente. Se aggiungo semplicemente un fornitore al componente e aggiungo le 2 istanze al costruttore, finisco con la stessa istanza di servizio. Per esempio:Angular2 DI: inizializzazione di più istanze diverse nello stesso costruttore

TestService

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

@Injectable() 
export class TestService { 

    public id: number = Math.random(); 

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

componente di prova

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

Risultato in consolle

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Id: 0.24242492129168425 
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB Id: 0.24242492129168425 

Qualcuno può dirmi se esiste un modo per utilizzare il meccanismo DI di Angular2 per iniettare più istanze di un servizio all'interno dello stesso componente o dovrei semplicemente rilasciare il DI per questo caso particolare e creare manualmente le mie istanze con un costruttore manuale?

Grazie in anticipo

risposta

3

È possibile iniettare una factory che restituisce una nuova istanza ogni volta che si chiama:

@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 (controllare l'output nella console del browser quando si fa clic sul pulsante)

+0

Sarebbe interessante per che cosa fosse il downvote. –

+2

Semplicemente non sta facendo il lavoro. Se si inietta con useFactory, il factory verrà utilizzato una sola volta per l'iniezione in _testServiceFactory. Ma questo frammento non funzionerà comunque, dato che non hai tipo per l'argomento del costruttore, angolare non può sapere cosa iniettare. –

+1

@TimKachko grazie mille per il vostro prezioso feedback! Ho aggiornato la mia risposta. Hai ragione, riguardo al tipo. L'ho modificato per usare una chiave stringa invece con '@Inject()'. La fabbrica funzionerà comunque. Forse potrei renderlo più ovvio nel codice, ma la factory è una funzione che restituisce una funzione, pertanto DI manterrà un'istanza della funzione restituita e la passerà a ogni classe che inietta ''testService'', e perché una funzione viene passato al costruttore che restituisce un 'nuovo TestService()' ogni volta che viene chiamato, questo funzionerà. –

2

I creerebbe un metodo statico che restituisce nuova istanza di servizio, e iniettare un solo tramite DI nel componente. Qualcosa di simile:

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

poi nel componente:

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

questo si inserisce anche il stile di codifica dai documenti del team di Angular 2. – BrianRT

+0

La cosa è dove memorizzi queste due istanze nel caso in cui gli altri componenti ne abbiano bisogno. –

10

Dato che non c'è quantità limitata di casi, il modo diretto può essere:

@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 
    ) {} 
    ... 
} 

O OpaqueToken controparte per evitare servizi override con lo stesso identificatore di stringa:

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

Non danneggia il DI nel costruttore TestService. E mantiene la testabilità di TestComponent alla pari, entrambe le istanze di servizio possono essere prese in giro in modo indipendente.

+2

Ottima risposta. Per completare, direi che OpaqueToken dovrebbe essere usato al posto delle stringhe per evitare conflitti di denominazione: https://angular.io/docs/ts/latest/api/core/index/OpaqueToken-class.html –

+0

@CharlesHETIER Grazie, gli identificatori di stringa sono stati usati qui per brevità, ma non fa male ricordare che OpaqueToken può essere usato pure. – estus

Problemi correlati