简体   繁体   中英

Dynamic loading of controller + factory in angularjs

I am developing angularjs application that should be possible to extend with "addins". In the simplified case addin is just a pair of js+html files. Each addin should have one or more controllers and one or more factories. Below is an example of adding with one controller and one factory:

JS:

angular.module('addins.basic', [])

angular.module('addins.basic').factory('BasicAddinFactory', [BasicAddinFactory]);

function BasicAddinFactory()
{
    var fact =
    {
        Invoke: function ()
        {
            console.log('BasicAddinFactory.Invoke');
        },
        GetClients: function ()
        {
            return ["aa", "bb"];
        }
    }

    return fact;
}

angular.module('addins.basic').controller('BasicAddinController', ['$scope', 'BasicAddinFactory', BasicAddinController]);

function BasicAddinController($scope, $injector, addin)
{
    //var injector = angular.injector(['ng', 'addins.basic'])
    //var addin = injector.get('BasicAddinFactory');

    $scope.expr = 'BasicAddinFactory: ' + addin.GetClients()[0];
}

HTML:

<div ng-controller="BasicAddinController">
    <input type="text" ng-model="expr">
    <span>{{ expr }}</span>
</div>

Loading addins dynamically is not an issue using techniques widely described on the internet: by adding JS script and HTML to the DOM. Everything loads fine until I try to inject dependency on BasicAddinFactory to BasicAddinController. After doing so I got error during dynamic loading: Unknown provider: addinProvider <- addin.

The interesting part is that if I do not explicitly inject dependency everything loads fine and I even can access factory instance from controller (or from the parent code that loads the "addin") by using commented code in the sample above. But that is quite ugly and I do not really want to have it like so.

I would appreciate if anyone could point me out where my mistake is.

Thanks.

UPDATE: Sample plunk

This has to do with how Angular actually handles dependencies behind the scenes. The bootstrap process handles registering all of your various services.

When you dynamically add modules you will need to register those new modules yourself. One way to do is having a globally available register function for each type of service like so:

app.config(['$controllerProvider',
  '$compileProvider', '$filterProvider', '$provide',
  function($controllerProvider,
    $compileProvider, $filterProvider, $provide) {

    app.register = {
      controller: $controllerProvider.register,
      directive: $compileProvider.directive,
      filter: $filterProvider.register,
      factory: $provide.factory,
      service: $provide.service
    };
  }
]);

You then change your dynamic modules to register their services like so:

app.register.factory('BasicAddinFactory', [BasicAddinFactory]);

A Plunker example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM