Reputation: 251
Here is my problem : I would like to make a single page application where AngularJS apps could be loaded/unloaded on the fly in a "main content" section, when clicking on different entries of a menu.
But I just can't figure out how to make this. I'm always getting the ng:btstrpd
error when using the angular.bootstrap
function.
I load the apps using the following code :
var mainContent = document.getElementById('main-content');
window.loadApp = function(modules) {
angular.bootstrap(mainContent, modules);
}
Here is a jsfiddle : http://jsfiddle.net/010b62ry/
I tried to remove the DOM element and reinsert it again but I get weird behaviors (like duplicates). I think the modules are not unloaded.
I also have tons of <!-- ngView: -->
comments while doing so.
Anyone has a good idea about how to implement this ? Bonus point if the memory gets released when switching from one application to another.
PS: I really need to bootstrap 100% independant modules (who manage their own routes etc) because some of them could be developed by other people who do not have access to the source code of this application. I just need to start their modules as 100% autonomous angular applications.
Upvotes: 3
Views: 2912
Reputation: 2369
i found this thread How to destroy an angularjs app?. Although I added code to recreate main-content div.
HTML code:
<nav>
<a onclick="loadApp(['app1'])">Load app n°1</a>
<a onclick="loadApp(['app2'])">Load app n°2</a>
</nav>
<div id="main-content-wrap">
<div id="main-content" class="app">
<div ng-view></div>
</div>
</div>
JS:
angular.module('app1', ['ngRoute']);
angular.module('app1')
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.otherwise({
template: 'hello app n°1'
});
}]);
angular.module('app2', ['ngRoute']);
angular.module('app2')
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.otherwise({
template: 'hello app n°2'
});
}]);
var mainContent = document.getElementById('main-content');
var mainContentWrap = document.getElementById('main-content-wrap');
var mainContentHTML = mainContentWrap.innerHTML;
window.loadApp = function(modules) {
if (window.currentApp) {
destroyApp(window.currentApp);
mainContentWrap.removeChild(mainContent);
mainContentWrap.innerHTML = mainContentHTML;
mainContent = document.getElementById('main-content');
}
window.currentApp = angular.bootstrap(mainContent, modules);
}
function destroyApp(app) {
/*
* Iterate through the child scopes and kill 'em
* all, because Angular 1.2 won't let us $destroy()
* the $rootScope
*/
var $rootScope = app.get('$rootScope');
var scope = $rootScope.$$childHead;
while (scope) {
var nextScope = scope.$$nextSibling;
scope.$destroy();
scope = nextScope;
}
/*
* Iterate the properties of the $rootScope and delete
* any that possibly were set by us but leave the
* Angular-internal properties and functions intact so we
* can re-use the application.
*/
for(var prop in $rootScope){
if (($rootScope[prop])
&& (prop.indexOf('$$') != 0)
&& (typeof($rootScope[prop]) === 'object')
) {
$rootScope[prop] = null;
}
}
}
And Fiddle http://jsfiddle.net/010b62ry/5/
It works but it looks like a black magic. I think it is much better to have one app and several controllers.
Upvotes: 2