Shannon Hochkins
Shannon Hochkins

Reputation: 12175

Can you inject dependencies into an existing angular app?

Lets say I have an app, which I don't know it's reference name or where it's defined.

Let's say I have another module which I've created, (nav module) I want to inject this nav module inside the existing angular app so that it can function as normal.

<html ng-app="appA">
  <body>
    <!-- navController exists inside another app -->
    <nav id="testElement" controller="navController"></nav>
  </body>
</html>

Example:

$(document).ready(function() {
    var nav = document.getElementById('testElement');
    if (!angular.element(nav).length) return;
    var appElement = angular.element('[ng-app]');
    console.log('appname', appElement.attr('ng-app'));
    var appToInject;
    if (!appElement.length) {
        // Manually run the new app from within js without a ng-app attrib
        appToInject = angular.module('CustomModuleForNavigation', []);
        angular.bootstrap(nav, ['CustomModuleForNavigation']);
    } else {
        appToInject = angular.module(appElement.attr('ng-app'),     []);
    }
    if (angular.isUndefined(appToInject)) return;
    console.log('winning?', appToInject)

    appToInject.controller('navController', function($scope) {
        console.log('extending app in new ctrl!', $scope);
    });

});

Upvotes: 2

Views: 836

Answers (2)

Balaji
Balaji

Reputation: 125

When there is an existing app module definition, but you want to add additional dependencies to the app module it can be done this way.

var existingModule = angular.module('appModuleName');
existingModule.requires.push('additionaldependency');

The appModuleName can be found by ng-app attribute of the index. Make sure this script runs right after the existing module definition script. Also, scripts required for 'additionaldependency' to be loaded before this script is loaded.

Upvotes: 2

Shannon Hochkins
Shannon Hochkins

Reputation: 12175

I have figured this out by injecting the dependency into an existing app, or manually running my own up with angular bootstrap.

var appElement = $('[ng-app]').first();
function angularJsModuleMerger(elementToBindScope, dependencies) {
    var scopeElement = document.getElementById(elementToBindScope);
    // Dependencies should contain our mobile scopeElement app only, the mobile app should contain it's dependencies.
    if (!angular.element(scopeElement).length) return;
    // If There is an existing angular app, inject our app into it, else, create a new app with our dependencies.
    var hasAngularApp = appElement.length;
    var appToInject;
    if (!hasAngularApp) {
        appToInject = angular.module('appForModularInjection', dependencies);
        // Manually run this app, so that we're not interrupting the current app.
    } else {
        // There is an existing app, so let's get it by it's name
        appToInject = angular.module(appElement.attr('ng-app'));
        // Inject our dependencies to the existing app, IF they don't alreay have these dependencies. 
        // Dependencies must also be loaded previously.
        var currentDependencies = appToInject.requires;
        var newDependencies = currentDependencies.concat(dependencies);
        appToInject.requires = newDependencies;
        appToInject.run(function($rootScope, $compile) {
            $compile(angular.element(scopeElement).contents())($rootScope);
        });
    }
    // If we still don't have an app, well, voodoo.
    if (angular.isUndefined(appToInject)) return;
    // console.log('ok');
    // We must run the app after all the declarations above for both existing and non existing apps.
    if (!hasAngularApp) angular.bootstrap(scopeElement, ['appForModularInjection']);
}

This will inject it self to an existing app, manually define an app and bind it all correctly to the element in question.

Scope/hierarchy is irrelevant.

Upvotes: 0

Related Questions