javascript - 动态加载 AngularJS Controller

标签 javascript angularjs

我有一个现有页面,我需要将一个带有可以动态加载的 Controller 的 Angular 应用放入其中。

这是一个片段,它根据 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。如果我正确理解 Bootstrap ,它返回的注入(inject)器应该知道 Foo 模块,对吧?

如果我改为使用 angular.injector(['ng', 'Foo']) 制作一个新的注入(inject)器,它似乎可以工作,但它会创建一个新的 $rootScope 不再与引导 Foo 模块的元素处于同一范围。

我是否使用了正确的功能来执行此操作,还是我遗漏了什么?我知道这不是按照 Angular 的方式进行的,但我需要将使用 Angular 的新组件添加到不使用 Angular 的旧页面,而且我不知道在引导模块时可能需要的所有组件。

更新:

我已经更新了 fiddle以表明我需要能够在不确定的时间点向页面添加多个 Controller 。

最佳答案

我找到了一个可能的解决方案,我不需要在引导之前了解 Controller :

// 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();
});

Fiddle .唯一的问题是您需要存储 $controllerProvider 并在不应该使用它的地方(在 Bootstrap 之后)使用它。此外,似乎没有一种简单的方法可以在注册之前获取用于定义 Controller 的函数,因此我需要遍历模块的 _invokeQueue,这是未记录的。

更新:要注册指令和服务,而不是 $controllerProvider.register 只需使用 $compileProvider.directive$provide .factory 分别。同样,您需要在初始模块配置中保存对这些的引用。

更新 2: Here's a fiddle它会自动注册所有加载的 Controller /指令/服务,而无需单独指定它们。

关于javascript - 动态加载 AngularJS Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15250644/

相关文章:

javascript - Google 图表添加不需要的文本

javascript - AngularJS - $http get 返回状态为 0 的错误?

javascript - AngularJS错误: Template for directive 'XXXXXX' must have exactly one root element

javascript - 保护 Angular 属性

javascript - Angularjs 模型仅在 View 中更改,而不在 Controller 中更改

javascript - 使用 Eclipse(推送插件)在 PhoneGAP 中推送通知 : Didn't get Registration ID

javascript - 停止动画时重置 jQuery 动画

javascript - Node js。创建连接的正确/最佳实践

javascript - 克服 !important 标签,使对话框可定位

javascript - 在 ng-repeat 中装饰 ng-click