Javascript 动态加载AngularJS控制器
我有一个现有的网页,我需要把一个角度应用程序与控制器,可以动态加载 下面是一个片段,它实现了我对如何基于API和我发现的一些相关问题进行的最佳猜测:Javascript 动态加载AngularJS控制器,javascript,angularjs,Javascript,Angularjs,我有一个现有的网页,我需要把一个角度应用程序与控制器,可以动态加载 下面是一个片段,它实现了我对如何基于API和我发现的一些相关问题进行的最佳猜测: // Make module Foo angular.module('Foo', []); // Bootstrap Foo var injector = angular.bootstrap($('body'), ['Foo']); // Make controller Ctrl in module Foo angular.module('Foo'
// 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);
});
//使模块成为Foo
角模('Foo',[]);
//Bootstrap-Foo
var injector=angular.bootstrap($('body'),['Foo']);
//使控制器在模块Foo中按Ctrl键
angular.module('Foo').controller('Ctrl',function(){});
//加载使用控制器Ctrl的元素
var ctrl=$('').appendTo('body');
//编译新元素
invoke(函数($compile,$rootScope){
//这里的链接器抛出异常
$compile(ctrl)($rootScope);
});
。请注意,这是对实际事件链的简化,在上面几行之间有各种异步调用和用户输入
当我尝试运行上述代码时,$compile返回的链接器抛出:参数“Ctrl”不是函数,未定义。如果我正确理解引导,它返回的注入器应该知道Foo
模块,对吗
相反,如果我使用angular.injector(['ng',Foo'])
创建一个新的注入器,它似乎可以工作,但它创建了一个新的$rootScope
,它不再与引导Foo
模块的元素的作用域相同
我是在使用正确的功能来完成这项工作,还是我遗漏了什么?我知道这不是以角度的方式进行的,但我需要将使用角度的新组件添加到不使用角度的旧页面,并且我不知道在引导模块时可能需要的所有组件
更新:
我已经更新了,以显示我需要能够在不确定的时间点向页面添加多个控制器。bootstrap()将为您调用AngularJS编译器,就像ng应用程序一样
// Make module Foo
angular.module('Foo', []);
// Make controller Ctrl in module Foo
angular.module('Foo').controller('Ctrl', function($scope) {
$scope.name = 'DeathCarrot' });
// Load an element that uses controller Ctrl
$('<div ng-controller="Ctrl">{{name}}</div>').appendTo('body');
// Bootstrap with Foo
angular.bootstrap($('body'), ['Foo']);
//使模块成为Foo
角模('Foo',[]);
//使控制器在模块Foo中按Ctrl键
角度.module('Foo').controller('Ctrl',function($scope){
$scope.name='DeathCarrot'});
//加载使用控制器Ctrl的元素
$({name}}').appendTo('body');
//Foo引导
引导($('body'),['Foo']);
.我找到了一个可能的解决方案,在引导之前我不需要了解控制器:
// 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();
});
//使模块Foo并将$controllerProvider存储在全局
var controllerProvider=null;
角度模块('Foo',[],函数($controllerProvider){
controllerProvider=$controllerProvider;
});
//Bootstrap-Foo
引导($('body'),['Foo']);
// .. 时光流逝。。
//使用Ctrl控制器加载javascript文件
角度.module('Foo').controller('Ctrl',function($scope,$rootScope){
$scope.msg=“它可以工作!rootScope是”+$rootScope.$id+
,应该是“+$('body')。scope().$id;
});
//加载包含使用Ctrl控制器的内容的html文件
$('')。附于('正文');
//手动注册Ctrl控制器
//如果可以直接引用控制器功能,只需运行:
//$controllerProvider.register(controllerName,controllerFunction);
//注意:在这个阶段,我还没有找到获取$controllerProvider的方法
//因此,我在运行模块配置时保留了一个引用
功能寄存器控制器(模块名称、控制器名称){
//在这里,我无法直接获取控制器函数,因此
//需要循环通过模块的_invokeQueue来获取它
var queue=angular.module(moduleName)。\u invokeQueue;
对于(var i=0;i,我刚刚改进了Jussi Kosunen编写的函数,以便只需一次调用即可完成所有工作
function registerController(moduleName, controllerName, template, container) {
// Load html file with content that uses Ctrl controller
$(template).appendTo(container);
// 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]);
}
}
angular.injector(['ng', 'Foo']).invoke(function($compile, $rootScope) {
$compile($('#ctrl'+controllerName))($rootScope);
$rootScope.$apply();
});
}
函数注册控制器(模块名称、控制器名称、模板、容器){
//加载包含使用Ctrl控制器的内容的html文件
$(模板).appendTo(容器);
//在这里,我无法直接获取控制器函数,因此
//需要循环通过模块的_invokeQueue来获取它
var queue=angular.module(moduleName)。\u invokeQueue;
对于(var i=0;i我建议看一看,它在现有模块上注册模块(或控制器、服务等)在运行时,我还需要添加多个视图,并在运行时从angularJs上下文之外的javascript函数将它们绑定到控制器,所以我想到了以下几点:
<div id="mController" ng-controller="mainController">
</div>
<div id="ee">
2nd controller's view should be rendred here
</div>
第二控制器的视图应在此处呈现
现在调用setCnt()函数将注入并编译html,它将链接到第二个控制器:
var app = angular.module('app', []);
function setCnt() {
// Injecting the view's html
var e1 = angular.element(document.getElementById("ee"));
e1.html('<div ng-controller="ctl2">my name: {{name}}</div>');
// Compile controller 2 html
var mController = angular.element(document.getElementById("mController"));
mController.scope().activateView(e1);
}
app.controller("mainController", function($scope, $compile) {
$scope.name = "this is name 1";
$scope.activateView = function(ele) {
$compile(ele.contents())($scope);
$scope.$apply();
};
});
app.controller("ctl2", function($scope) {
$scope.name = "this is name 2";
});
var-app=angular.module('app',[]);
函数setCnt(){
//注入视图的html
var e1=angular.element(document.getElementById(“ee”);
html('my name:{{{name}');
//编译控制器2 html
var mController=angular.element(document.getElementById(“mController”);
mController.scope().activateView(e1);
}
app.controller(“mainController”,函数($scope,$compile){
$scope.name=“这是名称1”;
$scope.activateView=函数(ele){
$compile(ele.contents())($scope);
$scope.$apply();
};
});
应用控制器(“ctl2”,功能($scope){
$scope.name=“这是名称2”;
});
下面是一个示例来测试这一点:
希望这有帮助
'use strict';
var mainApp = angular.module('mainApp', [
'ui.router',
'ui.bootstrap',
'ui.grid',
'ui.grid.edit',
'ngAnimate',
'headerModule',
'galleryModule',
'appointmentsModule',
]);
(function(){
var App = {
setControllers: mainApp.controller(controllers),
config: config.config(),
factories: {
authFactory: factories.auth(),
signupFactory: factories.signup(),
someRequestFactory: factories.saveSomeRequest(),
},
controllers: {
LoginController: controllers.userLogin(),
SignupController: controllers.signup(),
WhateverController: controllers.doWhatever(),
},
directives: {
signup: directives.signup(), // add new user
openLogin: directives.openLogin(), // opens login window
closeModal: directives.modalClose(), // close modal window
ngFileSelect: directives.fileSelect(),
ngFileDropAvailable: directives.fileDropAvailable(),
ngFileDrop: directives.fileDrop()
},
services: {
$upload: services.uploadFiles(),
}
};
})();
上面的代码只是一个示例
这样,您就不需要将ng controller=“someController”
放在页面的任何位置-您只需声明
相同的结构可用于每个模块或模块内部的模块为什么不使用配置和ui路由器
它在运行时加载,您无需在html代码中显示控制器
例如,类似下面的内容
var config = {
config: function(){
mainApp.config(function ($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise("/");
$stateProvider
.state('index',{
views:{
'main':{
controller: 'PublicController',
templateUrl: 'templates/public-index.html'
}
}
})
.state('public',{
url: '/',
parent: 'index',
views: {
'logo' : {templateUrl:'modules/header/views/logo.html'},
'title':{
controller: 'HeaderController',
templateUrl: 'modules/header/views/title.html'
},
'topmenu': {
controller: 'TopMenuController',
templateUrl: 'modules/header/views/topmenu.html'
},
'apartments': {
controller: 'FreeAptController',
templateUrl:'modules/free_apt/views/apartments.html'
},
'appointments': {
controller: 'AppointmentsController',
templateUrl:'modules/appointments/views/frm_appointments.html'
},
}
})
.state('inside',{
views:{
'main':{
controller: 'InsideController',
templateUrl: 'templates/inside-index.html'
},
},
resolve: {
factory:checkRouting
}
})
.state('logged', {
url:'/inside',
parent: 'inside',
views:{
'logo': {templateUrl: 'modules/inside/views/logo.html'},
'title':{templateUrl:'modules/inside/views/title.html'},
'topmenu': {
// controller: 'InsideTopMenuController',
templateUrl: 'modules/inside/views/topmenu.html'
},
'messages': {
controller: 'MessagesController',
templateUrl: 'modules/inside/modules/messages/views/initial-view-messages.html'
},
'requests': {
//controller: 'RequestsController',
//templateUrl: 'modules/inside/modules/requests/views/initial-view-requests.html'
},
}
})
});
},
};
这就是我所做的,实际上分为两部分,使用ng controller及其范围定义函数,然后使用$controller服务创建动态控制器:-
首先,HTML-我们需要一个静态控制器,它将实例化一个动态控制器
<div ng-controller='staticCtrl'>
<div ng-controller='dynamicCtrl'>
{{ dynamicStuff }}
</div>
</div>
.controller('staticCtrl', ['$scope', '$controller', function($scope, $controller) {
$scope.dynamicCtrl = function() {
var fn = eval('(function ($scope, $rootScope) { alert("I am dynamic, my $scope.$id = " + $scope.$id + ", $rootScope.$id = " + $rootScope.$id); })');
return $controller(fn, { $scope: $scope.$new() }).constructor;
}
}])