AngularJS:延迟加载控制器和内容

在这个简化的场景中,我有两个文件:index.htm,lazy.htm。

index.htm的:

var myApp = angular.module('myApp', []); myApp.controller('embed',function($scope){ $scope.embed = 'Embedded Controller'; }); 
{{embed}}

lazy.htm

 myApp.controller('lazy',function($scope){ $scope.lazy = 'Lazy Controller'; }); 
{{lazy}}

结果是一个错误:“Argument’lazy’不是函数,未定义”

改为使用函数

lazy.htm

 function lazy($scope) { $scope.lazy = 'Lazy Controller'; } 
{{lazy}}

这可以使用到版本1.3 beta 14.在beta 15中删除了全局控制器function: https : //github.com/angular/angular.js/issues/8296

那么现在,动态获取lazy.htm的愤怒内容的更好方法是什么?

更新:

在本文( http://ify.io/lazy-loading-in-angularjs )中,我找到了另一种可能的解决方案。 $ controllerProvider允许我们在角度引导之后注册新的控制器。 奇迹般有效。 在v1.3.0-beta.18中测试

index.htm的:

 var myApp = angular.module('myApp', []) .controller('embed',function($scope){ $scope.embed = 'Embedded Controller'; }) .config(function($controllerProvider) { myApp.cp = $controllerProvider; }); 
{{embed}}

lazy.htm

 myApp.cp.register('lazy',function($scope){ $scope.lazy = 'Lazy Controller'; }); 
{{lazy}}

更新2:

另外两个有效的替代方案是:

lazy.htm

 _app = $('[ng-app]').scope(); _app.lazy = function($scope) { $scope.lazy = 'Lazy Controller'; }; 

要么

 var $rootScope = $('[ng-app]').injector().get('$rootScope'); $rootScope.lazy = function($scope) { $scope.lazy = 'Lazy Controller'; }; 

但我相信最后两个例子不应该用于制作。

您还可以使用jquery解析$ routeProvider

app.js

 /* Module Creation */ var app = angular.module ('app', ['ngRoute']); app.config(['$routeProvider', '$controllerProvider', function($routeProvider, $controllerProvider){ /*Creating a more synthesized form of service of $ controllerProvider.register*/ app.registerCtrl = $controllerProvider.register; function loadScript(path) { var result = $.Deferred(), script = document.createElement("script"); script.async = "async"; script.type = "text/javascript"; script.src = path; script.onload = script.onreadystatechange = function (_, isAbort) { if (!script.readyState || /loaded|complete/.test(script.readyState)) { if (isAbort) result.reject(); else result.resolve(); } }; script.onerror = function () { result.reject(); }; document.querySelector("head").appendChild(script); return result.promise(); } function loader(arrayName){ return { load: function($q){ var deferred = $q.defer(), map = arrayName.map(function(name) { return loadScript('js/controllers/'+name+".js"); }); $q.all(map).then(function(r){ deferred.resolve(); }); return deferred.promise; } }; } $routeProvider .when('/', { templateUrl: 'views/foo.html', resolve: loader(['foo']) }) .when('/bar',{ templateUrl: 'views/bar.html', controller: 'BarCtrl', resolve: loader(['bar']) }) .otherwise({ redirectTo: document.location.pathname }); }]); 

/views/foo.html

 
{{text}}

JS /控制器/ foo.js

 /*Here we use the synthesized version of $controllerProvider.register to register the controller in view*/ app.registerCtrl('FooCtrl',function($scope){ $scope.text = 'Test'; }); 

/views/bar.html

 
{{text2}}

JS /控制器/ bar.js

 app.registerCtrl('BarCtrl',function($scope){ $scope.text2 = 'Test'; }); 

起初我使用了AndréBetiolo的答案。 但是,它并不总是有效,因为ajax加载是非阻塞的,导致视图有时在加载脚本之前请求控制器。

作为一种解决方案,我强制该函数在成功加载所有脚本之前不返回。 这是一种hackish,但确保在完成解决之前负载是成功的。 它还允许加载多个控制器。

app.js

 var app = angular.module ('app', ['ngRoute']); app.config(['$routeProvider', '$controllerProvider', function($routeProvider, $controllerProvider){ /*Creating a more synthesized form of service of $ controllerProvider.register*/ app.registerCtrl = $controllerProvider.register; //jquery to dynamically include controllers as needed function controllers(controllers){ var numLoaded = 0; for (i = 0; i < controllers.length; i++) { $.ajaxSetup({async:false}); $.getScript('js/controllers/' + controllers[i] + '.js').success(function(){ numLoaded++; if (numLoaded == controllers.length) { return true; //only return after all scripts are loaded, this is blocking, and will fail if all scripts aren't loaded. } }); } } $routeProvider .when('/', { templateUrl: 'views/foo.html', resolve: { load: function () { controllers(['foo']) } } }) .when('/bar',{ templateUrl: 'views/bar.html', controller: 'BarCtrl', resolve: { load: function () { controllers(['bar','foo']) //you can load multiple controller files } } }) .otherwise({ redirectTo: document.location.pathname }); }]); 

/views/foo.html

 
{{text}}

/views/bar.html

 
{{text2}}
{{text}}

/controllers/bar.js

 app.registerCtrl('BarCtrl',function($scope){ $scope.text2 = 'Test'; }); 

//// JConfig文件——–

 window.angularApp.config(function ($routeProvider,$controllerProvider,$compileProvider,$provide, azMessages) { $routeProvider.when('/login', { resolve: { load: ['$q', '$rootScope', function ($q, $rootScope) { var deferred = $q.defer(); require([ //load required Js file here ], function () { $rootScope.$apply(function () { deferred.resolve(); }); }); return deferred.promise; } ] } }); $routeProvider.otherwise({ redirectTo: '/login' }); window.angularApp.components = { controller: $controllerProvider.register, service: $provide.service, directive: $compileProvider.directive } 

// contoller声明

 angularApp.components.controller('DiscussionController',[function(){ }]); 

你可以有纯粹的AngularJS延迟加载。

创建“LazyService”:

 var ng = angular.module('app'); ng.factory('lazyService', [ '$http', function($http) { var jsPath = 'js/${ name }.js'; var promisesCache = {}; return { loadScript: function(name) { var path = jsPath.replace('${ name }', name); var promise = promisesCache[name]; if (!promise) { promise = $http.get(path); promisesCache[name] = promise; return promise.then(function(result) { eval(result.data); console.info('Loaded: ' + path); }); } return promise; } } }]); 

然后,定义您的配置:

 var ng = angular.module('app', [ 'ngRoute' ]); ng.config([ '$routeProvider', '$controllerProvider', '$provide', function($routeProvider, $controllerProvider, $provide) { // Lazy loading ng.lazy = { controller: $controllerProvider.register, //directive: $compileProvider.directive, //filter: $filterProvider.register, factory: $provide.factory, service: $provide.service } $routeProvider .when('/', { templateUrl: 'view/home.html' }) .when('/vendor', { templateUrl: 'view/vendor.html', resolve: { svc: [ 'lazyService', function(lazyService) { return lazyService.loadScript('services/vendor'); }], ctrl: [ 'lazyService', function(lazyService) { return lazyService.loadScript('controllers/vendor'); }] } }); . . . 

在“js / services / vendor.js”上,创建服务:

 var ng = angular.module('app'); ng.lazy.service('vendorService', [ function() { . . . 

在“js / controllers / vendor.js”上,将控制器创建为:

 var ng = angular.module('app'); ng.lazy.controller('vendorController', [ function() { . . . 

定义哪些promise应在路由加载之前解析时的“resolve”属性。

做你要求的最好方法是改为使用指令并将控制器和模板绑定在一起,以便在适当的时候绑定它。 目前,绑定它不会在正确的时间发生在lazy.htm中,除非您声明了第二个示例中显示的全局函数。

理想情况下 – Angular将强制您将HTML和JS分开,因为在较新的版本中,这可能会更频繁地强制执行。

您可能必须使用requireJS http://solutionoptimist.com/2013/09/30/requirejs-angularjs-dependency-injection/

你可以尝试一下伎俩

 ng-controller-controller="'lazy'" 

要么

在HTML中

NG-控制器控制器= “myObject.controller”

某处注入

 $scope.myObject.controller = $controller('lazy', {$scope: $scope}) 

试试Angular JS的这个ARI 插件 。 它可以帮助您根据需要延迟加载控制器脚本。

您还可以使用Directives加载控制器!

这里的一个例子:

https://gist.github.com/raphaelluchini/53d08ed1331e47aa6a87

我发给你样例代码。 它对我来说很好。 所以请检查一下:

 var myapp = angular.module('myapp', ['ngRoute']); /* Module Creation */ var app = angular.module('app', ['ngRoute']); app.config(['$routeProvider', '$controllerProvider', function ($routeProvider, $controllerProvider) { app.register = { controller: $controllerProvider.register, //directive: $compileProvider.directive, //filter: $filterProvider.register, //factory: $provide.factory, //service: $provide.service }; // 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) { app.register.controller(controllerName, call[2][1]); } } } var tt = { loadScript: function (path) { var result = $.Deferred(), script = document.createElement("script"); script.async = "async"; script.type = "text/javascript"; script.src = path; script.onload = script.onreadystatechange = function (_, isAbort) { if (!script.readyState || /loaded|complete/.test(script.readyState)) { if (isAbort) result.reject(); else { result.resolve(); } } }; script.onerror = function () { result.reject(); }; document.querySelector(".shubham").appendChild(script); return result.promise(); } } function stripScripts(s) { var div = document.querySelector(".shubham"); div.innerHTML = s; var scripts = div.getElementsByTagName('script'); var i = scripts.length; while (i--) { scripts[i].parentNode.removeChild(scripts[i]); } return div.innerHTML; } function loader(arrayName) { return { load: function ($q) { stripScripts(''); // This Function Remove javascript from Local var deferred = $q.defer(), map = arrayName.map(function (obj) { return tt.loadScript(obj.path) .then(function () { registerController(obj.module, obj.controller); }) }); $q.all(map).then(function (r) { deferred.resolve(); }); return deferred.promise; } }; }; $routeProvider .when('/first', { templateUrl: '/Views/foo.html', resolve: loader([{ controller: 'FirstController', path: '/MyScripts/FirstController.js', module: 'app' }, { controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' }]) }) .when('/second', { templateUrl: '/Views/bar.html', resolve: loader([{ controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' }, { controller: 'A', path: '/MyScripts/anotherModuleController.js', module: 'myapp' }]) }) .otherwise({ redirectTo: document.location.pathname }); }]) 

在HTML页面中:

   

感谢你