ponownie otwórz i dodaj zależności do już załadowanej aplikacji

89

Czy istnieje sposób na wstrzyknięcie późnej zależności do już załadowanego modułu kątowego? Oto o co mi chodzi:

Załóżmy, że mam aplikację kątową obejmującą całą witrynę, zdefiniowaną jako:

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

I na każdej stronie:

<html ng-app="App">

Później ponownie otwieram aplikację, aby dodać logikę w oparciu o potrzeby bieżącej strony:

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

Teraz mówią, że jeden z tych bitów na żądanie logiki wymaga również własne zależności (jak ngTouch, ngAnimate, ngResourceitp). Jak mogę dołączyć je do aplikacji podstawowej? To nie wydaje się działać:

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

Zdaję sobie sprawę, że mogę wszystko zrobić z góry, tj.

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

Lub zdefiniuj każdy moduł osobno, a następnie wstrzyknij wszystko do głównej aplikacji ( zobacz tutaj po więcej ):

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

Ale będzie to wymagało za każdym razem zainicjowania aplikacji z zależnościami bieżącej strony.

Wolę to podstawowy app.jsw każdej strony i po prostu przedstawić wymaganych rozszerzeń (na każdej stronie reports.js, home.jsitp), bez konieczności rewizji za każdym logiczny ładującego dodać lub usunąć coś.

Czy istnieje sposób na wprowadzenie zależności, gdy aplikacja jest już załadowana? Jaki jest idiomatyczny sposób (lub sposoby), aby to zrobić? Skłaniam się ku temu drugiemu rozwiązaniu, ale chciałem sprawdzić, czy sposób, który opisałem, również da się zrobić. dzięki.

sa125
źródło
Czy możesz dać mi swój ostatni działający kod, żeby go obejrzeć?
Mangu Singh Rajpurohit
@ user2393267 mmm, było tak długo, nie mam pojęcia, czy nadal mam ten kod ... Przepraszam. Myślę, że w końcu wróciłem do projektu, ponieważ zwykle kiedy muszę się włamać, oznacza to, że nie robię tego dobrze ... Jednak jeśli nadal jesteś zdeterminowany, aby kontynuować to podejście, odpowiedź poniżej wydaje się dobrym tropem .
sa125

Odpowiedzi:

115

Rozwiązałem to w ten sposób:

ponownie odwołaj się do aplikacji:

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

następnie umieść nowe wymagania w tablicy wymagań:

app.requires.push('newDependency');
AlBaraa Sh
źródło
3
To działa dla mnie +1 Użyłem tego do wielu zależności, takich jak app.requires.push ('doctorCtrl', 'doctorService');
Amir
8
To uratowało moją architekturę.
Saeed Neamati
3
Na mnie to nie działa. Dodam zależność dynamicznie zgodnie z opisem, ale Angular nadal nie może znaleźć usługi z dodanego modułu.
Slava Fomin II
6
I app.requiresjest tablicą, więc jeśli dodajesz wiele zależności (jak w przykładzie Reports), przekazujesz je jako oddzielne argumenty do pushmetody: app.requires.push('ui.event', 'ngResource');lub jeśli twoje dodatkowe zależności są już tablicą:Array.prototype.push.apply(app.requires, ['ui.event', 'ngResource'])
The Red Pea
2
Czasami pomijam głosowanie, ponieważ nie chcę się logować, nie tym razem! Dzięki!
CularBytes,
12

Proste ... Pobierz instancję modułu za pomocą metody pobierania w następujący sposób: var app = angular.module ("App");

Następnie dodaj do kolekcji „require” w następujący sposób: app.requires [app.requires.length] = "ngResource";

W każdym razie to zadziałało dla mnie. POWODZENIA!

David Donovan
źródło
4
To zadziałało dla mnie! Mam pytanie - dlaczego nie użyć: app.requires.push ("ngResource")?
Philipp Munin
9

Zgodnie z tą propozycją w grupie Google Angular JS ta funkcjonalność nie istnieje w tej chwili. Miejmy nadzieję, że główny zespół zdecyduje się dodać tę funkcję, przydałby się sam.

Matt Nibecker
źródło
4
Tak, wydaje się to szczególnie przydatne dla osób, które niekoniecznie chcą budować SPA.
regularmike
4

Jeśli chcesz dodać wiele zależności jednocześnie, możesz przekazać je w trybie push w następujący sposób:

<script>
    var app = angular.module('appName');
    app.requires.push('dependencyCtrl1', 'dependencyService1');
</script>
Amir
źródło
4

Zdaję sobie sprawę, że to stare pytanie, jednak nie otrzymałem jeszcze działającej odpowiedzi, więc postanowiłem podzielić się, jak je rozwiązałem.

Rozwiązanie wymaga rozwidlenia Angulara, więc nie możesz już używać CDN. Jednak modyfikacja jest bardzo mała, więc jestem zaskoczony, dlaczego ta funkcja nie istnieje w Angular.

Skorzystałem z linku do grup Google, który został podany w jednej z pozostałych odpowiedzi na to pytanie. Tam znalazłem następujący kod, który rozwiązał problem:

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

Kiedy dodałem ten kod do linii 4414 w kątowym kodzie źródłowym 1.5.0 (wewnątrz createInjectorfunkcji, przed return instanceInjector;instrukcją), umożliwiło mi to dodanie zależności po załadowaniu w ten sposób $injector.loadNewModules(['ngCookies']);.

tjespe
źródło
? Co jest nie tak z największą liczbą głosów (stan na 26.06.2017) ? Wygląda na to, że został dostarczony ponad rok przed opublikowaniem tego; czy twoja odpowiedź ma jakąś przewagę?
The Red Pea
@TheRedPea Cóż, nie ma w tym nic złego, poza tym, że nie rozwiązało mojego problemu, ale ta odpowiedź tak
tjespe
I to nie zadziałało, ponieważ, jak sądzę, już uruchomiłeś swoją aplikację? Ja też to zauważyłem ...
Red Pea
2
Po przeczytaniu linku do posta w Społeczności Google jestem jeszcze bardziej pewien, że bootstrap jest powodem, dla którego takie rozwiązanie jest konieczne. Głosowanie za mną, ponieważ pierwotne pytanie dotyczyło „już załadowanej aplikacji”, której nikt inny nie rozwiązuje (w rzeczywistości OP mógł się pomylić)
The Red Pea
1

Od wersji 1.6.7 możliwe jest teraz opóźnione ładowanie modułów po załadowaniu aplikacji przy użyciu $injector.loadNewModules([modules]). Poniżej przykład zaczerpnięty z dokumentacji AngularJS:

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

Przeczytaj pełną dokumentację dotyczącą loadNewModules ponieważ istnieje kilka pułapek wokół niego.

Jest też bardzo dobra przykładowa aplikacja omkadiri, która używa jej z routerem ui.

Denis Pshenov
źródło