En lugar de eso, simplemente llene la tabla con "sí" y "no" sin explicación, voy a entrar en un poco más de detalle.
[Nota, agregada después de terminar: esto terminó siendo ... bastante más largo de lo que esperaba. Hay un tl; dr en la parte inferior, pero espero que esto sea informativo.]
[Esta respuesta también se ha agregado a la wiki de AngularJS: comprensión de la inyección de dependencia ]
El $provide
servicio es responsable de decirle a Angular cómo crear nuevas cosas inyectables; Estas cosas se llaman servicios . Los servicios se definen por cosas llamadas proveedores , que es lo que estás creando cuando las usas $provide
. La definición de un proveedor se realiza a través del provider
método en el $provide
servicio, y puede obtener el $provide
servicio solicitando que se inyecte en la config
función de una aplicación . Un ejemplo podría ser algo como esto:
app.config(function($provide) {
$provide.provider('greeting', function() {
this.$get = function() {
return function(name) {
alert("Hello, " + name);
};
};
});
});
Aquí hemos definido un nuevo proveedor para un servicio llamado greeting
; podemos inyectar una variable nombrada greeting
en cualquier función inyectable (como controladores, más sobre eso más adelante) y Angular llamará a la $get
función del proveedor para devolver una nueva instancia del servicio. En este caso, lo que se inyectará es una función que toma un name
parámetro y alert
un mensaje basado en el nombre. Podríamos usarlo así:
app.controller('MainController', function($scope, greeting) {
$scope.onClick = function() {
greeting('Ford Prefect');
};
});
Ahora aquí está el truco. factory
,, service
y value
son solo accesos directos para definir varias partes de un proveedor, es decir, proporcionan un medio para definir un proveedor sin tener que escribir todo eso. Por ejemplo, podría escribir exactamente ese mismo proveedor así:
app.config(function($provide) {
$provide.factory('greeting', function() {
return function(name) {
alert("Hello, " + name);
};
});
});
Es importante entenderlo, así que lo reformularé: bajo el capó, AngularJS está llamando exactamente el mismo código que escribimos anteriormente (la $provide.provider
versión) para nosotros. Literalmente, 100% no hay diferencia en las dos versiones. value
funciona de la misma manera: si lo que devolviéramos de nuestra $get
función (también conocida como nuestra factory
función) es siempre exactamente igual, podemos escribir aún menos código usando value
. Por ejemplo, dado que siempre devolvemos la misma función para nuestro greeting
servicio, también podemos usarla value
para definirla:
app.config(function($provide) {
$provide.value('greeting', function(name) {
alert("Hello, " + name);
});
});
Nuevamente, esto es 100% idéntico a los otros dos métodos que hemos usado para definir esta función: es solo una forma de guardar algo de escritura.
Ahora probablemente notaste esta app.config(function($provide) { ... })
cosa molesta que he estado usando. Dado que la definición de nuevos proveedores (a través de cualquiera de los métodos anteriores) es muy común, AngularJS expone los $provider
métodos directamente en el objeto del módulo, para ahorrar aún más tipeo:
var myMod = angular.module('myModule', []);
myMod.provider("greeting", ...);
myMod.factory("greeting", ...);
myMod.value("greeting", ...);
Todos estos hacen lo mismo que las app.config(...)
versiones más detalladas que utilizamos anteriormente.
El inyectable que me he saltado hasta ahora es constant
. Por ahora, es bastante fácil decir que funciona igual value
. Veremos que hay una diferencia más tarde.
Para revisar , todas estas piezas de código están haciendo exactamente lo mismo:
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);
});
El inyector es responsable de crear instancias de nuestros servicios utilizando el código que proporcionamos $provide
(sin juego de palabras). Cada vez que escribe una función que toma argumentos inyectados, está viendo el inyector en funcionamiento. Cada aplicación AngularJS tiene un único $injector
que se crea cuando se inicia por primera vez; puede obtenerlo inyectándose $injector
en cualquier función inyectable (sí, ¡ $injector
sabe cómo inyectarse!)
Una vez que lo haya hecho $injector
, puede obtener una instancia de un servicio definido al llamarlo get
con el nombre del servicio. Por ejemplo,
var greeting = $injector.get('greeting');
greeting('Ford Prefect');
El inyector también es responsable de inyectar servicios en funciones; por ejemplo, puede inyectar servicios mágicamente en cualquier función que tenga usando el invoke
método del inyector ;
var myFunction = function(greeting) {
greeting('Ford Prefect');
};
$injector.invoke(myFunction);
Vale la pena señalar que el inyector solo creará una instancia de un servicio una vez . Luego almacena en caché lo que el proveedor devuelve por el nombre del servicio; la próxima vez que solicite el servicio, obtendrá exactamente el mismo objeto.
Entonces, para responder a su pregunta, puede inyectar servicios en cualquier función que se llame$injector.invoke
. Esto incluye
- funciones de definición del controlador
- funciones de definición de directivas
- funciones de definición de filtro
- Los
$get
métodos de los proveedores (también conocidos como las factory
funciones de definición)
Como constant
sys value
siempre devuelven un valor estático, no se invocan a través del inyector y, por lo tanto, no puede inyectarles nada.
Configurar proveedores
Usted puede preguntarse por qué alguien se molestaría en configurar un proveedor de pleno derecho con el provide
método si factory
, value
, etc, son mucho más fácil. La respuesta es que los proveedores permiten mucha configuración. Ya hemos mencionado que cuando crea un servicio a través del proveedor (o cualquiera de los accesos directos que Angular le brinda), crea un nuevo proveedor que define cómo se construye ese servicio. ¡Lo que no mencioné es que estos proveedores pueden inyectarse en config
secciones de su aplicación para que pueda interactuar con ellos!
Primero, Angular ejecuta su aplicación en dos fases: las fases config
y run
. La config
fase, como hemos visto, es donde puede configurar cualquier proveedor según sea necesario. Aquí también se configuran las directivas, los controladores, los filtros y similares. La run
fase, como puede suponer, es donde Angular realmente compila su DOM e inicia su aplicación.
Puede agregar código adicional para que se ejecute en estas fases con las funciones myMod.config
y myMod.run
, cada una toma una función para ejecutarse durante esa fase específica. Como vimos en la primera sección, estas funciones son inyectables: inyectamos el servicio incorporado $provide
en nuestro primer ejemplo de código. Sin embargo, lo que vale la pena destacar es que durante la config
fase, solamente los proveedores pueden ser inyectadas (con la excepción de los servicios en el AUTO
module-- $provide
y $injector
).
Por ejemplo, lo siguiente no está permitido :
myMod.config(function(greeting) {
// WON'T WORK -- greeting is an *instance* of a service.
// Only providers for services can be injected in config blocks.
});
A lo que sí tiene acceso es a cualquier proveedor de servicios que haya realizado:
myMod.config(function(greetingProvider) {
// a-ok!
});
Hay una excepción importante: los constant
s, dado que no se pueden cambiar, pueden inyectarse dentro de los config
bloques (así es como difieren de los value
s). Se accede a ellos solo por su nombre (no es Provider
necesario el sufijo).
Cada vez que define un proveedor para un servicio, ese proveedor recibe un nombre serviceProvider
, donde service
está el nombre del servicio. ¡Ahora podemos usar el poder de los proveedores para hacer cosas más complicadas!
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');
});
Ahora tenemos una función en nuestro proveedor llamada setText
que podemos usar para personalizar nuestro alert
; Podemos acceder a este proveedor en un config
bloque para llamar a este método y personalizar el servicio. Cuando finalmente ejecutamos nuestra aplicación, podemos obtener el greeting
servicio y probarlo para ver que nuestra personalización entró en vigencia.
Dado que este es un ejemplo más complejo, aquí hay una demostración de trabajo: http://jsfiddle.net/BinaryMuse/9GjYg/
Las funciones del controlador pueden inyectarse, pero los controladores mismos no pueden inyectarse en otras cosas. Esto se debe a que los controladores no se crean a través del proveedor. En cambio, hay un servicio angular incorporado llamado $controller
que es responsable de configurar sus controladores. Cuando llama myMod.controller(...)
, en realidad está accediendo al proveedor de este servicio , al igual que en la última sección.
Por ejemplo, cuando define un controlador como este:
myMod.controller('MainController', function($scope) {
// ...
});
Lo que realmente estás haciendo es esto:
myMod.config(function($controllerProvider) {
$controllerProvider.register('MainController', function($scope) {
// ...
});
});
Más tarde, cuando Angular necesita crear una instancia de su controlador, usa el $controller
servicio (que a su vez usa el $injector
para invocar la función de su controlador para que también inyecte sus dependencias).
Filtros y Directivas
filter
y directive
funciona exactamente de la misma manera que controller
; filter
usa un servicio llamado $filter
y su proveedor $filterProvider
, mientras que directive
usa un servicio llamado $compile
y su proveedor $compileProvider
. Algunos enlaces:
Según los otros ejemplos, myMod.filter
y myMod.directive
son atajos para configurar estos servicios.
Entonces, para resumir, cualquier función con la que se llame $injector.invoke
puede inyectarse . Esto incluye, de su gráfico (pero no se limita a):
- controlador
- directiva
- fábrica
- filtrar
- proveedor
$get
(cuando se define proveedor como un objeto)
- función de proveedor (cuando se define proveedor como una función de constructor)
- Servicio
El proveedor crea nuevos servicios que pueden inyectarse en las cosas . Esto incluye:
- constante
- fábrica
- proveedor
- Servicio
- valor
Dicho esto, a los servicios integrados les gusta $controller
y $filter
pueden inyectarse, y puede usar esos servicios para obtener los nuevos filtros y controladores que definió con esos métodos (a pesar de que las cosas que definió no son, por sí mismas, capaces de ser inyectado en las cosas).
Aparte de eso, cualquier función inyector-invocado puede ser inyectado con cualquier servicio de proveedor-proporcionado - no hay ninguna restricción (aparte de la config
y run
diferencias aparecen en este documento).