我有一个现有页面,需要在其中添加一个可以动态加载的控制器的角度应用程序。
这是一个片段,它根据API和我发现的一些相关问题实现了关于如何完成操作的最佳猜测:
// Make module Foo angular.module('Foo', []); // Bootstrap Foo var injector = angular.bootstrap($('body'), ['Foo']); // Make controller Ctrl in module Foo angular.module('Foo').controller('Ctrl', function() { }); // Load an element that uses controller Ctrl var ctrl = $('<div ng-controller="Ctrl">').appendTo('body'); // compile the new element injector.invoke(function($compile, $rootScope) { // the linker here throws the exception $compile(ctrl)($rootScope); });
JSFiddle。请注意,这是对实际事件链的简化,在以上各行之间有各种异步调用和用户输入。
当我尝试运行上述代码时,由$ compile返回的链接器将抛出:Argument 'Ctrl' is not a function, got undefined。如果我正确地理解了引导程序,那么它返回的注射器应该知道该Foo模块,对吗?
Argument 'Ctrl' is not a function, got undefined
Foo
相反,如果我使用制作了一个新的注入器angular.injector(['ng', 'Foo']),它似乎可以工作,但是会创建一个新的注入器,该注入器$rootScope的范围不再与Foo引导该模块的元素相同。
angular.injector(['ng', 'Foo'])
$rootScope
我是在使用正确的功能来执行此操作还是错过了某些功能?我知道这不是Angular的方法,但是我需要在不使用Angular的旧页面中添加使用Angular的新组件,而且我不知道引导模块时可能需要的所有组件。
更新:
我已经更新了小提琴,以表明我需要能够在不确定的时间点向页面添加多个控制器。
我找到了一种可能的解决方案,在引导时无需了解控制器:
// Make module Foo and store $controllerProvider in a global var controllerProvider = null; angular.module('Foo', [], function($controllerProvider) { controllerProvider = $controllerProvider; }); // Bootstrap Foo angular.bootstrap($('body'), ['Foo']); // .. time passes .. // Load javascript file with Ctrl controller angular.module('Foo').controller('Ctrl', function($scope, $rootScope) { $scope.msg = "It works! rootScope is " + $rootScope.$id + ", should be " + $('body').scope().$id; }); // Load html file with content that uses Ctrl controller $('<div id="ctrl" ng-controller="Ctrl" ng-bind="msg">').appendTo('body'); // Register Ctrl controller manually // If you can reference the controller function directly, just run: // $controllerProvider.register(controllerName, controllerFunction); // Note: I haven't found a way to get $controllerProvider at this stage // so I keep a reference from when I ran my module config function registerController(moduleName, controllerName) { // Here I cannot get the controller function directly so I // need to loop through the module's _invokeQueue to get it var queue = angular.module(moduleName)._invokeQueue; for(var i=0;i<queue.length;i++) { var call = queue[i]; if(call[0] == "$controllerProvider" && call[1] == "register" && call[2][0] == controllerName) { controllerProvider.register(controllerName, call[2][1]); } } } registerController("Foo", "Ctrl"); // compile the new element $('body').injector().invoke(function($compile, $rootScope) { $compile($('#ctrl'))($rootScope); $rootScope.$apply(); });
小提琴。唯一的问题是,您需要存储,$controllerProvider并在确实不应该使用它的地方(在引导程序之后)使用它。同样,在注册之前,似乎还没有一种简单的方法来获得用于定义控制器的函数,因此我需要遍历模块_invokeQueue中未记录的。
$controllerProvider
_invokeQueue
更新: 注册指令和服务,而不是分别$controllerProvider.register简单地使用$compileProvider.directive和$provide.factory。同样,您需要在初始模块配置中保存对这些引用的引用。
$controllerProvider.register
$compileProvider.directive
$provide.factory
UDPATE 2: 这是一个小提琴,可以自动注册所有加载的控制器/指令/服务,而无需单独指定它们。