Quali “cose” possono essere iniettate in altri in Angular.js?

Sto avendo un po ‘di difficoltà a comprendere l’iniezione di dipendenza in angular. Quindi la mia domanda è: qualcuno può spiegare quale dei “tipi”, come Controller, Factory, Provider, ecc. Possiamo iniettare in altri, incluse altre istanze dello stesso “tipo”?

Quello che sto cercando in realtà è questa tabella piena di y / n. Per le celle con la stessa riga / colonna, significa iniettare il valore di un “tipo” in un altro con lo stesso “tipo”

+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+ | Can we inject? | Constant | Controller | Directive | Factory | Filter | Provider | Service | Value | +----------------+----------+------------+-----------+---------+--------+----------+---------+-------+ | Constant | | | | | | | | | | Controller | | | | | | | | | | Directive | | | | | | | | | | Factory | | | | | | | | | | Filter | | | | | | | | | | Provider | | | | | | | | | | Service | | | | | | | | | | Value | | | | | | | | | +----------------+----------+------------+-----------+---------+--------+----------+---------+-------+ 

Piuttosto che basta compilare il tavolo con “sì” e “no” senza spiegazione, entrerò un po ‘più in dettaglio.

[Nota, aggiunta dopo aver terminato: questo ha finito per essere … un po ‘più lungo di quanto mi aspettassi. C’è un tl; dr in basso, ma spero che questo risulti informativo.]

[Questa risposta è stata aggiunta anche al wiki AngularJS: Understanding Injection Dependency ]


Il fornitore ( $provide )

Il servizio $provide è responsabile di dire ad Angular come creare nuove cose iniettabili; queste cose sono chiamate servizi . I servizi sono definiti da cose chiamate provider , che è ciò che stai creando quando usi $provide . La definizione di un provider viene effettuata tramite il metodo provider sul servizio $provide , e puoi ottenere il servizio $provide chiedendo che venga iniettato nella funzione di config dell’applicazione. Un esempio potrebbe essere qualcosa del genere:

 app.config(function($provide) { $provide.provider('greeting', function() { this.$get = function() { return function(name) { alert("Hello, " + name); }; }; }); }); 

Qui abbiamo definito un nuovo provider per un servizio chiamato greeting ; possiamo iniettare una variabile denominata greeting in qualsiasi funzione iniettabile (come i controller, più su quella successiva) e Angular chiamerà la funzione $get del provider per restituire una nuova istanza del servizio. In questo caso, la cosa che verrà iniettata è una funzione che accetta un parametro name e alert un messaggio in base al nome. Potremmo usarlo in questo modo:

 app.controller('MainController', function($scope, greeting) { $scope.onClick = function() { greeting('Ford Prefect'); }; }); 

Ora ecco il trucco. factory , service e value sono solo scorciatoie per definire le varie parti di un fornitore, cioè forniscono un mezzo per definire un fornitore senza dover digitare tutto quel materiale. Ad esempio, potresti scrivere lo stesso provider esattamente come questo:

 app.config(function($provide) { $provide.factory('greeting', function() { return function(name) { alert("Hello, " + name); }; }); }); 

È importante capire, quindi riformulerò: sotto il cofano, AngularJS sta chiamando lo stesso identico codice che abbiamo scritto sopra (la versione $provide.provider ) per noi. C’è letteralmente, il 100% nessuna differenza nelle due versioni. value funziona allo stesso modo – se qualunque cosa torneremmo dalla nostra funzione $get (ovvero la nostra funzione di factory ) è sempre esattamente la stessa, possiamo scrivere anche meno codice usando il value . Ad esempio, poiché restituiamo sempre la stessa funzione per il nostro servizio di greeting , possiamo anche usare il value per definirlo:

 app.config(function($provide) { $provide.value('greeting', function(name) { alert("Hello, " + name); }); }); 

Ancora una volta, questo è identico al 100% agli altri due metodi che abbiamo usato per definire questa funzione – è solo un modo per risparmiare un po ‘di digitazione.

Ora probabilmente hai notato questa fastidiosa app.config(function($provide) { ... }) cosa ho usato. Poiché la definizione di nuovi provider (tramite uno dei metodi sopra indicati) è così comune, AngularJS espone i metodi $provider direttamente sull’object modulo, per risparmiare ancora più digitazione:

 var myMod = angular.module('myModule', []); myMod.provider("greeting", ...); myMod.factory("greeting", ...); myMod.value("greeting", ...); 

Questi hanno tutti la stessa funzione delle versioni più dettagliate di app.config(...) abbiamo usato in precedenza.

L’iniettabile che ho saltato finora è constant . Per ora, è abbastanza facile dire che funziona proprio come il value . Vedremo che c’è una differenza dopo.

Per verificare , tutti questi pezzi di codice stanno facendo esattamente la stessa cosa:

 myMod.provider('greeting', function() { this.$get = function() { return function(name) { alert("Hello, " + name); }; }; }); myMod.factory('greeting', function() { return function(name) { alert("Hello, " + name); }; }); myMod.value('greeting', function(name) { alert("Hello, " + name); }); 

The Injector ( $injector )

L’iniettore è responsabile della creazione effettiva di istanze dei nostri servizi utilizzando il codice fornito tramite $provide (nessun gioco di parole previsto). Ogni volta che scrivi una funzione che accetta argomenti iniettati, stai vedendo l’iniettore al lavoro. Ogni applicazione AngularJS ha un singolo $injector che viene creato all’avvio dell’applicazione; puoi ottenerlo iniettando $injector in qualsiasi funzione iniettabile (sì, $injector sa come iniettarsi!)

Una volta ottenuto $injector , è ansible ottenere un’istanza di un servizio definito chiamando su di esso con il nome del servizio. Per esempio,

 var greeting = $injector.get('greeting'); greeting('Ford Prefect'); 

L’iniettore è anche responsabile per l’iniezione di servizi in funzioni; ad esempio, è ansible iniettare magicamente servizi in qualsiasi funzione che si utilizza il metodo di invoke dell’iniettore;

 var myFunction = function(greeting) { greeting('Ford Prefect'); }; $injector.invoke(myFunction); 

Vale la pena notare che l’iniettore creerà solo un’istanza di un servizio una sola volta . Quindi memorizza nella cache qualsiasi cosa il provider restituisca dal nome del servizio; la prossima volta che chiedi il servizio, otterrai effettivamente lo stesso identico object.

Quindi, per rispondere alla tua domanda, puoi inserire servizi in qualsiasi funzione chiamata $injector.invoke . Ciò comprende

  • funzioni di definizione del controller
  • funzioni di definizione della direttiva
  • funzioni di definizione del filtro
  • i metodi $get dei provider (ovvero le funzioni di definizione della factory )

Poiché la constant s e il value s restituiscono sempre un valore statico, non vengono invocati tramite l’iniettore e quindi non è ansible iniettarli con nulla.

Configurazione dei provider

Ci si potrebbe chiedere perché qualcuno si preoccupi di creare un fornitore a pieno titolo con il metodo di offerta se factory , value , ecc. Sono molto più semplici. La risposta è che i provider consentono molta configurazione. Abbiamo già detto che quando si crea un servizio tramite il provider (o qualsiasi scorciatoia che Angular fornisce), si crea un nuovo provider che definisce come viene costruito quel servizio. Quello che non ho menzionato è che questi provider possono essere iniettati nelle sezioni di config della tua applicazione in modo da poter interagire con loro!

Innanzitutto, Angular esegue l’applicazione in due fasi: la config e le fasi di run . La fase di config , come abbiamo visto, è dove è ansible impostare qualsiasi provider, se necessario. Questo è anche il punto in cui vengono impostate le direttive, i controller, i filtri e così via. La fase di run , come puoi immaginare, è dove Angular effettivamente compila il tuo DOM e avvia la tua app.

È ansible aggiungere altro codice da eseguire in queste fasi con le funzioni myMod.config e myMod.run , ognuna delle myMod.config myMod.run una funzione da eseguire durante quella fase specifica. Come abbiamo visto nella prima sezione, queste funzioni sono iniettabili – abbiamo iniettato il servizio $provide built integrato nel nostro primo esempio di codice. Tuttavia, ciò che vale la pena notare è che durante la fase di config , solo i provider possono essere iniettati (ad eccezione dei servizi nel modulo AUTO– $provide e $injector ).

Ad esempio, non è consentito quanto segue:

 myMod.config(function(greeting) { // WON'T WORK -- greeting is an *instance* of a service. // Only providers for services can be injected in config blocks. }); 

Ciò a cui hai accesso sono tutti i fornitori di servizi che hai effettuato:

 myMod.config(function(greetingProvider) { // a-ok! }); 

C’è un’eccezione importante: le constant s, dato che non possono essere modificate, possono essere iniettate all’interno dei blocchi di config (questo è il modo in cui differiscono dal value s). Sono accessibili solo dal loro nome (non è necessario il suffisso Provider ).

Ogni volta che viene definito un provider per un servizio, tale provider riceve serviceProvider denominato, dove service è il nome del servizio. Ora possiamo usare il potere dei provider di fare cose più complicate!

 myMod.provider('greeting', function() { var text = 'Hello, '; this.setText = function(value) { text = value; }; this.$get = function() { return function(name) { alert(text + name); }; }; }); myMod.config(function(greetingProvider) { greetingProvider.setText("Howdy there, "); }); myMod.run(function(greeting) { greeting('Ford Prefect'); }); 

Ora abbiamo una funzione sul nostro provider chiamata setText che possiamo usare per personalizzare il nostro alert ; possiamo accedere a questo provider in un blocco di config per chiamare questo metodo e personalizzare il servizio. Quando finalmente eseguiamo la nostra app, possiamo prendere il servizio di greeting e provarlo per vedere che la nostra personalizzazione ha avuto effetto.

Poiché questo è un esempio più complesso, ecco una dimostrazione pratica : http://jsfiddle.net/BinaryMuse/9GjYg/

Controller ( $controller )

Le funzioni del controller possono essere iniettate, ma i controller stessi non possono essere iniettati in altre cose. Questo perché i controller non vengono creati tramite il provider. Invece, c’è un servizio angular incorporato chiamato $controller che è responsabile della configurazione dei controller. Quando chiami myMod.controller(...) , stai effettivamente accedendo al provider di questo servizio , proprio come nell’ultima sezione.

Ad esempio, quando definisci un controller come questo:

 myMod.controller('MainController', function($scope) { // ... }); 

Quello che stai facendo in realtà è questo:

 myMod.config(function($controllerProvider) { $controllerProvider.register('MainController', function($scope) { // ... }); }); 

Successivamente, quando Angular deve creare un’istanza del controller, utilizza il servizio $controller (che a sua volta utilizza $injector per richiamare la funzione controller in modo che anche le sue dipendenze vengano iniettate).

Filtri e direttive

filter e directive funzionano esattamente allo stesso modo del controller ; filter usa un servizio chiamato $filter e il suo provider $filterProvider , mentre directive usa un servizio chiamato $compile e il suo provider $compileProvider . Alcuni link:

Come per gli altri esempi, myMod.filter e myMod.directive sono scorciatoie per configurare questi servizi.


tl; dr

Quindi, per riassumere, qualsiasi funzione che viene chiamata con $injector.invoke può essere iniettata in . Questo include, dal tuo grafico (ma non è limitato a):

  • controllore
  • direttiva
  • fabbrica
  • filtro
  • provider $get (quando si definisce il provider come object)
  • funzione provider (quando si definisce il provider come funzione di costruzione)
  • servizio

Il fornitore crea nuovi servizi che possono essere iniettati in cose . Ciò comprende:

  • costante
  • fabbrica
  • fornitore
  • servizio
  • valore

Detto questo, i servizi integrati come $controller e $filter possono essere iniettati, e puoi usare quei servizi per ottenere i nuovi filtri e controller che hai definito con quei metodi (anche se le cose che hai definito non sono, da sole , in grado di essere iniettato nelle cose).

Oltre a ciò, qualsiasi funzione invocata dall’iniettore può essere iniettata con qualsiasi servizio fornito dal provider – non vi sono restrizioni (oltre alla config e alle differenze di run qui elencate).

Il punto che BinaryMuse fa nella sua sorprendente risposta su fornitori, fabbriche e servizi è la stessa cosa estremamente importante.

Di seguito un’immagine che penso possa illustrare visivamente il suo punto:

AngularJS sono tutti solo provider http://www.simplygoodcode.com/wp-content/uploads/2015/11/angularjs-provider-service-factory-highlight.png

Ottima risposta di Michelle. Voglio solo far notare che le direttive possono essere iniettate. Se hai una direttiva denominata myThing , puoi inserirla con myThingDirective : Ecco un esempio myThingDirective .

L’esempio sopra non è molto pratico, tuttavia la capacità di iniettare una direttiva è utile quando si vuole decorare quella direttiva .