reabra e adicione dependências a um aplicativo já inicializado

89

Existe uma maneira de injetar uma dependência tardia em um módulo angular já inicializado? Aqui está o que quero dizer:

Digamos que eu tenha um aplicativo angular para todo o site, definido como:

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

E em cada página:

<html ng-app="App">

Mais tarde, estou reabrindo o aplicativo para adicionar lógica com base nas necessidades da página atual:

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

Agora, dizer que um desses bits on-demand da lógica também requer suas próprias dependências (como ngTouch, ngAnimate, ngResource, etc). Como posso anexá-los ao aplicativo base? Isso não parece funcionar:

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

Sei que posso fazer tudo com antecedência, ou seja -

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

Ou defina cada módulo por conta própria e, em seguida, injete tudo no aplicativo principal ( veja mais aqui ):

// 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'])

Mas isso exigirá que eu inicialize o aplicativo todas as vezes com as dependências da página atual.

Eu prefiro para incluir o básico app.jsem cada página e simplesmente introduzir as extensões necessárias para cada página ( reports.js, home.js, etc), sem ter que rever a toda lógica bootstrapping adicionar ou remover alguma coisa.

Existe uma maneira de introduzir dependências quando o aplicativo já está inicializado? Qual é a forma (ou formas) idiomática de fazer isso? Estou inclinado para a última solução, mas queria ver se a maneira que descrevi também poderia ser feita. obrigado.

sa125
fonte
Você pode me dar seu código de trabalho final, para dar uma olhada?
Mangu Singh Rajpurohit
@ user2393267 mmm, faz tanto tempo que não tenho ideia se ainda tenho esse código ... Desculpe. Acho que acabei revisando o design, porque normalmente quando tenho que hackear as coisas significa que não estou fazendo certo ... No entanto, se você ainda está determinado a seguir essa abordagem, a resposta abaixo parece uma boa pista .
sa125

Respostas:

115

Eu resolvi assim:

consulte o aplicativo novamente:

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

em seguida, coloque seus novos requisitos na matriz de requisitos:

app.requires.push('newDependency');
AlBaraa Sh
fonte
3
Isso funciona para mim +1 eu usei isso para várias dependências, como app.requires.push ('doctorCtrl', 'doctorService');
Amir de
8
Isso salvou minha arquitetura.
Saeed Neamati
3
Não está funcionando para mim. Estou adicionando a dependência dinamicamente conforme descrito, mas o Angular ainda não consegue encontrar um serviço do módulo adicionado.
Slava Fomin II
6
E app.requiresé uma matriz, portanto, se você estiver adicionando várias dependências (como no exemplo do seu Reports), você os passa como argumentos separados para o pushmétodo: app.requires.push('ui.event', 'ngResource');ou se suas dependências adicionais já são uma matriz:Array.prototype.push.apply(app.requires, ['ui.event', 'ngResource'])
The Red Pea
2
Às vezes, pulo a votação porque não quero fazer o login, não desta vez! Obrigado!
CularBytes de
12

Simples ... Obtenha uma instância do módulo usando o getter como este: var app = angular.module ("App");

Em seguida, adicione à coleção "requer" como este: app.requires [app.requires.length] = "ngResource";

Enfim, isso funcionou para mim. BOA SORTE!

David Donovan
fonte
4
Isso funcionou para mim! Eu tenho uma pergunta - por que não usar: app.requires.push ("ngResource")?
Philipp Munin,
9

De acordo com esta proposta no grupo Angular JS do google esta funcionalidade não existe até o momento. Espero que a equipe principal decida adicionar esta funcionalidade, possa usá-la eu mesmo.

Matt Nibecker
fonte
4
Sim, isso parece especialmente útil para pessoas que não querem necessariamente construir um SPA.
sessão regular de
4

Se desejar adicionar várias dependências de uma vez, você pode passá-las em push da seguinte maneira:

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

Sei que essa é uma questão antiga, no entanto, nenhuma resposta funcional foi fornecida ainda, então decidi compartilhar como resolvi isso.

A solução requer bifurcação Angular, então você não pode mais usar o CDN. No entanto, a modificação é muito pequena, então estou surpreso porque esse recurso não existe no Angular.

Segui o link para grupos do Google que foi fornecido em uma das outras respostas a esta pergunta. Lá encontrei o seguinte código, que resolveu o problema:

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

Quando adicionei esse código à linha 4414 no código-fonte do angular 1.5.0 (dentro da createInjectorfunção, antes da return instanceInjector;instrução), ele me permitiu adicionar dependências após a inicialização como esta $injector.loadNewModules(['ngCookies']);.

tjespe
fonte
? O que há de errado com a resposta com maior votação (em 26/06/2017) ? Parece que foi fornecido mais de um ano antes de você postar; sua resposta tem alguma vantagem?
The Red Pea de
@TheRedPea Bem, não há nada de errado com isso, exceto que não resolveu meu problema, mas esta resposta
resolveu
E não funcionou para você porque, eu estou supondo, você já havia inicializado seu aplicativo? Eu observei isso também ...
The Red Pea
2
Depois de ler o link da postagem da Comunidade do Google, tenho ainda mais certeza de que o bootstrap é o motivo pelo qual uma solução como essa é necessária. Votação positiva porque a pergunta original feita sobre um "aplicativo já inicializado", que ninguém mais aborda (na verdade, o OP pode ter falado incorretamente)
The Red Pea
1

Desde a versão 1.6.7 agora é possível carregar lentamente os módulos após o aplicativo ter sido inicializado usando $injector.loadNewModules([modules]). Abaixo está um exemplo tirado da documentação do AngularJS:

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

Por favor, leia a documentação completa sobre loadNewModules, pois existem algumas dicas sobre ele.

Há também um aplicativo de amostra muito bom da omkadiri usando-o com o ui-router.

Denis Pshenov
fonte