reabrir y agregar dependencias a una aplicación ya iniciada

89

¿Hay alguna manera de inyectar una dependencia tardía a un módulo angular ya iniciado? Esto es lo que quiero decir:

Digamos que tengo una aplicación angular en todo el sitio, definida como:

// in app.js
var App = angular.module("App", []);

Y en cada página:

<html ng-app="App">

Más tarde, reabriré la aplicación para agregar lógica según las necesidades de la página actual:

// in reports.js
var App = angular.module("App")
App.controller("ReportsController", ['$scope', function($scope) {
  // .. reports controller code
}])

Ahora, decir que uno de esos bits a la carta de la lógica también requiere sus propias dependencias (como ngTouch, ngAnimate, ngResource, etc). ¿Cómo puedo adjuntarlos a la aplicación base? Esto no parece funcionar:

// in reports.js
var App = angular.module("App", ['ui.event', 'ngResource']); // <-- raise error when App was already bootstrapped

Me doy cuenta de que puedo hacer todo por adelantado, es decir,

// in app.js
var App = angular.module("App", ['ui.event', 'ngResource', 'ngAnimate', ...]);

O defina cada módulo por sí solo y luego inyecte todo en la aplicación principal ( consulte aquí para obtener más información ):

// in reports.js
angular.module("Reports", ['ui.event', 'ngResource'])
.controller("ReportsController", ['$scope', function($scope) {
  // .. reports controller code
}])

// in home.js
angular.module("Home", ['ngAnimate'])
.controller("HomeController", ['$scope', '$http', function($scope, $http){
  // ...
}])

// in app.js, loaded last into the page (different for every page that varies in dependencies)
var App = angular.module("App", ['Reports', 'Home'])

Pero esto requerirá que inicialice la aplicación cada vez con las dependencias de la página actual.

Yo prefiero incluir el básico app.jsen cada página y simplemente presento las extensiones necesarias para cada página ( reports.js, home.js, etc.), sin tener que revisar la lógica de arranque cada vez que puedo añadir o eliminar algo.

¿Hay alguna forma de introducir dependencias cuando la aplicación ya está iniciada? ¿Cuál se considera la forma (o formas) idiomáticas de hacer esto? Me inclino hacia la última solución, pero quería ver si la forma que describí también se podría hacer. Gracias.

sa125
fuente
¿Puede darme su código de trabajo final para que le eche un vistazo?
Mangu Singh Rajpurohit
@ user2393267 mmm, ha pasado tanto tiempo, no tengo idea si todavía tengo ese código ... Lo siento. Creo que finalmente revisé el diseño, porque generalmente cuando tengo que revisar las cosas, significa que no lo estoy haciendo bien ... Sin embargo, si aún está decidido a seguir este enfoque, la respuesta a continuación parece una buena pista .
sa125

Respuestas:

115

Lo resolví así:

referencia la aplicación nuevamente:

var app = angular.module('app');

luego empuje sus nuevos requisitos a la matriz de requisitos:

app.requires.push('newDependency');
AlBaraa Sh
fuente
3
Esto funciona para mí +1 Lo usé para múltiples dependencias como app.requires.push ('doctorCtrl', 'doctorService');
Amir
8
Esto salvó mi arquitectura.
Saeed Neamati
3
No está funcionando para mi. Estoy agregando la dependencia dinámicamente como se describe, pero Angular aún no puede encontrar un servicio desde el módulo agregado.
Slava Fomin II
6
Y app.requireses una matriz, por lo que si está agregando varias dependencias (como en su ejemplo de Informes), las pasa como argumentos separados al pushmétodo: app.requires.push('ui.event', 'ngResource');o si sus dependencias adicionales ya son una matriz:Array.prototype.push.apply(app.requires, ['ui.event', 'ngResource'])
The Red Pea
2
A veces me salto la votación porque no quiero iniciar sesión, ¡no esta vez! ¡Gracias!
CularBytes
12

Simple ... Obtenga una instancia del módulo usando el getter como este: var app = angular.module ("App");

Luego agregue a la colección "requiere" de esta manera: app.requires [app.requires.length] = "ngResource";

De todos modos, esto funcionó para mí. ¡BUENA SUERTE!

David Donovan
fuente
4
¡Eso funcionó para mí! Tengo una pregunta: ¿por qué no usar: app.requires.push ("ngResource")?
Philipp Munin
9

Según esta propuesta en el grupo de google de Angular JS esta funcionalidad no existe a partir de este momento. Con suerte, el equipo central decide agregar esta funcionalidad, podría usarla yo mismo.

Matt Nibecker
fuente
4
Sí, esto parece especialmente útil para las personas que no necesariamente quieren construir un SPA.
regularmike
4

Si desea agregar varias dependencias a la vez, puede pasarlas en push de la siguiente manera:

<script>
    var app = angular.module('appName');
    app.requires.push('dependencyCtrl1', 'dependencyService1');
</script>
Amir
fuente
4

Me doy cuenta de que esta es una pregunta antigua, sin embargo, aún no se ha proporcionado una respuesta funcional, por lo que decidí compartir cómo la resolví.

La solución requiere bifurcar Angular, por lo que ya no puede usar CDN. Sin embargo, la modificación es muy pequeña, por lo que me sorprende que esta función no exista en Angular.

Seguí el enlace a los grupos de Google que se proporcionó en una de las otras respuestas a esta pregunta. Allí encontré el siguiente código, que resolvió el problema:

instanceInjector.loadNewModules = function (mods) {
  forEach(loadModules(mods), function(fn) { instanceInjector.invoke(fn || noop); });
};

Cuando agregué este código a la línea 4414 en el código fuente angular 1.5.0 (dentro de la createInjectorfunción, antes de la return instanceInjector;declaración), me permitió agregar dependencias después de arrancar de esta manera $injector.loadNewModules(['ngCookies']);.

tjespe
fuente
? ¿Qué pasa con la respuesta más votada (a partir del 26/6/2017) ? Parece que se proporcionó más de un año antes de que publicara esto; ¿Tu respuesta tiene alguna ventaja?
The Red Pea
@TheRedPea Bueno, no hay nada de malo en ello, excepto que no resolvió mi problema, pero esta respuesta sí lo hizo
tjespe
¿Y no funcionó para usted porque, supongo, ya había arrancado su aplicación? También observé eso ...
The Red Pea
2
Después de leer la publicación de la Comunidad de Google vinculada, estoy aún más seguro de que el bootstrapping es la razón por la que es necesaria una solución como esta. Votación a favor porque la pregunta original era sobre una "aplicación ya iniciada", que nadie más aborda (de hecho, el OP puede haber hablado mal)
The Red Pea
1

Desde la versión 1.6.7, ahora es posible cargar módulos de forma diferida después de que la aplicación haya sido arrancada usando $injector.loadNewModules([modules]). A continuación se muestra un ejemplo tomado de la documentación de AngularJS:

app.factory('loadModule', function($injector) {
   return function loadModule(moduleName, bundleUrl) {
     return getScript(bundleUrl).then(function() { $injector.loadNewModules([moduleName]); });
   };
})

Lea la documentación completa sobre loadNewModules, ya que existen algunas trampas.

También hay una muy buena aplicación de muestra de omkadiri que la usa con ui-router.

Denis Pshenov
fuente