riaprire e aggiungere dipendenze a un'applicazione già avviata


89

C'è un modo per iniettare una dipendenza tardiva a un modulo angolare già avviato? Ecco cosa intendo:

Supponiamo che io disponga di un'app angolare a livello di sito, definita come:

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

E in ogni pagina:

<html ng-app="App">

Successivamente, riaprirò l'app per aggiungere logica in base alle esigenze della pagina corrente:

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

Ora, dire che una di quelle punte on-demand della logica richiede anche le proprie dipendenze (come ngTouch, ngAnimate, ngResource, ecc). Come posso collegarli all'app di base? Questo non sembra funzionare:

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

Mi rendo conto di poter fare tutto in anticipo, ovvero -

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

Oppure definisci ogni modulo da solo e poi inserisci tutto nell'app principale ( vedi qui per ulteriori informazioni ):

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

Ma questo richiederà di inizializzare l'app ogni volta con le dipendenze della pagina corrente.

Io preferisco includere la base app.jsdi ogni pagina e semplicemente introdurre le estensioni necessarie per ogni pagina ( reports.js, home.js, ecc), senza la necessità di rivedere la logica di ogni bootstrap posso aggiungere o rimuovere qualcosa.

C'è un modo per introdurre dipendenze quando l'app è già avviata? Qual è considerato il modo (o i modi) idiomatici per farlo? Sono propenso a quest'ultima soluzione, ma volevo vedere se si potesse fare anche il modo che ho descritto. Grazie.


Puoi darmi il tuo codice di lavoro finale, per dare un'occhiata?
Mangu Singh Rajpurohit

@ user2393267 mmm, è passato così tanto tempo, non ho idea se ho ancora quel codice ... Scusate. Penso di aver finalmente rivisitato il design, perché di solito quando devo hackerare le cose significa che non lo sto facendo bene ... Tuttavia, se sei ancora determinato a perseguire questo approccio, la risposta di seguito sembra un buon vantaggio .
sa125

Risposte:


115

L'ho risolto in questo modo:

fare nuovamente riferimento all'app:

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

quindi invia i tuoi nuovi requisiti all'array dei requisiti:

app.requires.push('newDependency');

3
Questo funziona per me +1 L'ho usato per dipendenze multiple come app.requires.push ('doctorCtrl', 'doctorService');
Amir

8
Questo ha salvato la mia architettura.
Saeed Neamati

3
Non funziona per me. Sto aggiungendo la dipendenza dinamicamente come descritto, ma Angular non riesce ancora a trovare un servizio dal modulo aggiunto.
Slava Fomin II

6
Ed app.requiresè un array, quindi se stai aggiungendo più dipendenze (come nell'esempio di Reports), le passi come argomenti separati al pushmetodo: app.requires.push('ui.event', 'ngResource');o se le tue dipendenze aggiuntive sono già un array:Array.prototype.push.apply(app.requires, ['ui.event', 'ngResource'])
The Red Pea

2
A volte salto la votazione perché non voglio accedere, non questa volta! Grazie!
CularBytes

12

Semplice ... Ottieni un'istanza del modulo usando il getter in questo modo: var app = angular.module ("App");

Quindi aggiungi alla raccolta "richiede" in questo modo: app.requires [app.requires.length] = "ngResource";

Comunque, questo ha funzionato per me. IN BOCCA AL LUPO!


4
Ha funzionato per me! Ho una domanda: perché non utilizzare: app.requires.push ("ngResource")?
Philipp Munin


4

Se desideri aggiungere più dipendenze contemporaneamente, puoi passarle in push come segue:

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

4

Mi rendo conto che questa è una vecchia domanda, tuttavia, non è stata ancora fornita alcuna risposta funzionante, quindi ho deciso di condividere come l'ho risolta.

La soluzione richiede il fork di Angular, quindi non puoi più usare CDN. Tuttavia la modifica è molto piccola, quindi sono sorpreso del motivo per cui questa funzione non esiste in Angular.

Ho seguito il collegamento ai gruppi di Google che è stato fornito in una delle altre risposte a questa domanda. Lì ho trovato il seguente codice, che ha risolto il problema:

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

Quando ho aggiunto questo codice alla riga 4414 nel codice sorgente angolare 1.5.0 (all'interno della createInjectorfunzione, prima return instanceInjector;dell'istruzione), mi ha permesso di aggiungere dipendenze dopo il bootstrap in questo modo $injector.loadNewModules(['ngCookies']);.


? Cosa c'è di sbagliato nella risposta più votata (al 26/6/2017) ? Sembra che sia stato fornito più di un anno prima che lo pubblicassi; la tua risposta ha qualche vantaggio?
The Red Pea

@TheRedPea Beh, non c'è niente di sbagliato in esso, tranne che non ha risolto il mio problema, ma questa risposta lo ha fatto
tjespe

E non ha funzionato per te perché, immagino, avevi già avviato la tua app? L'ho notato anche io ...
The Red Pea

2
Dopo aver letto il post della community di Google linkato, sono ancora più sicuro che il bootstrap sia il motivo per cui è necessaria una soluzione come questa. Upvoting perché la domanda originale chiedeva "un'applicazione già avviata", a cui nessun altro si rivolge (in effetti l'OP potrebbe aver pronunciato male)
The Red Pea

1

Dalla versione 1.6.7 è ora possibile caricare in modo lento i moduli dopo che l'app è stata avviata utilizzando $injector.loadNewModules([modules]). Di seguito è riportato un esempio tratto dalla documentazione di AngularJS:

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

Si prega di leggere la documentazione completa su loadNewModules poiché ci sono alcuni trucchi intorno ad esso.

C'è anche un'ottima app di esempio di omkadiri che la utilizza con ui-router.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.