2012-11-28 7 views
20

Il caso d'uso è semplice: ho due controller che condividono la stessa dipendenza MyService. Questo servizio contiene uno stato, lascia sat myVariable. Se lo imposto da ControllerOne, verrà individuato anche da ControllerTwo.Dica ad AngularJs di restituire una nuova istanza tramite Dipendenza iniezione

Quello che voglio è che ogni controller abbia la propria istanza di MyService, in modo che myVariable possa essere modificato da ciascun Controller senza influenzare l'altro.

Per dirla in un altro parole - voglio nuova istanza essere restituito da Dependency Injection, piuttosto che Singleton.

+0

Vedi anche http://stackoverflow.com/a/13620494/215945 –

risposta

20

Non esattamente come si potrebbe sperare. Le istanze di servizio vengono create la prima volta che vengono recuperate dall'iniettore e gestite dall'iniettore ... in altre parole, sono sempre singleton. The magic happens in here, in particolare la funzione provider, che inserisce l'istanza del provider nell'oggetto providerCache.

Ma non perdere la speranza, si potrebbe altrettanto facilmente aggiungere i costruttori per qualunque cosa sia che si desidera condividere in un servizio, se così scelto:

app.factory('myService', [function() { 
    var i = 1; 

    function Foo() { 
     this.bar = "I'm Foo " + i++; 
    }; 

    return { 
      Foo: Foo 
    }; 
}]); 

app.controller('Ctrl1', function($scope, myService) { 
    $scope.foo = new myService.Foo(); 
    console.log($scope.foo.bar) //I'm Foo 1 
}); 

app.controller('Ctrl2', function($scope, myService) { 
    $scope.foo = new myService.Foo(); 
    console.log($scope.foo.bar) //I'm Foo 2 
}); 

EDIT: come l'OP ha sottolineato, c'è anche lo $injector.instantiate, che puoi usare per chiamare i costruttori JavaScript al di fuori del tuo controller. Non sono sicuro di quali siano le implicazioni della testabilità qui, ma ti offre un altro modo per iniettare il codice che costruirà un nuovo oggetto per te.

+4

C'è anche un altro modo. Puoi semplicemente creare un oggetto con le dipendenze necessarie (Componente X) e poi iniettarlo direttamente con '$ injector.instantiate (ComponentX, {})'. Il secondo argomento può contenere tutte le variabili 'statefull'. Semplice ed elegante, grazie Angular Js! Forse potresti aggiungerlo alla tua risposta come soluzione alternativa, per favore? –

+1

Sembra difficile da testare. –

+0

Sembra essere la soluzione, ma è necessario restituire solo il costruttore. Tutti gli altri metodi che potresti rendere da parte non influenzeranno mai le istanze che creerai in seguito, tranne se li aggiungi al prototipo del tuo costruttore ... Vedi la risposta di karlgold, che è quasi perfetta. –

3

Ci sono un sacco di opzioni generali per modularizzando codice JavaScript, ma se si vuole fare qualcosa che si basa esclusivamente su AngularJS, questo modello funziona:

1) In primo luogo definire la classe che si desidera iniettare più volte:

function MyClass() { 
    // ... 
} 

MyClass.prototype.memberMethod = function() { 
    // ... 
} 

2) Quindi, rendere il costruttore a disposizione come una costante:

angular.module('myModule').constant('MyClass', MyClass); 

3) Infine, utilizzare il modello di fabbrica per creare denominate, le istanze iniettabili della classe:

angular.module('myOtherModule', ['myModule']).factory('instanceOfMyClass', [ 
    'MyClass', 
    function(MyClass) { return new MyClass(); } 
]); 
+0

Buona idea. Ma questo non funziona se il tuo prototipo ha bisogno di iniezioni che non possono essere fatte con costanti, né valori ... In questo caso, credo che la creazione di un servizio sia un'opzione migliore. –

Problemi correlati