3

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.

1
  • Possibly not closely related, i had a question posted sometime back with a different issue. It has a demo.. Not sure might provide some clues.. stackoverflow.com/questions/25537396/… Commented Oct 1, 2014 at 17:09

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.