Angularjs 仅在需要时动态注入模块
我将Require.js与Angular.js结合使用 一些控制器需要巨大的外部依赖项,而其他控制器则不需要,例如,Angularjs 仅在需要时动态注入模块,angularjs,requirejs,Angularjs,Requirejs,我将Require.js与Angular.js结合使用 一些控制器需要巨大的外部依赖项,而其他控制器则不需要,例如,FirstController需要。这至少是额外的135 kb: require([ "angular", "angular.ui.codemirror" // requires codemirror itself ], function(angular) { angular.module("app", [ ..., "ui.codemirror" ]).control
FirstController
需要。这至少是额外的135 kb:
require([
"angular",
"angular.ui.codemirror" // requires codemirror itself
], function(angular) {
angular.module("app", [ ..., "ui.codemirror" ]).controller("FirstController", [ ... ]);
});
我不希望每次加载页面时都必须包含指令和Codemirror库,只是为了让Angular满意。这就是为什么我现在只在点击路线时加载控制器 然而,当我需要像
define([
"app",
"angular.ui.codemirror"
], function(app) {
// ui-codemirror directive MUST be available to the view of this controller as of now
app.lazy.controller("FirstController", [
"$scope",
function($scope) {
// ...
}
]);
});
我如何告诉Angular将ui.codemirr
模块(或任何其他模块)也注入到应用程序模块中?我不在乎这是否是一种黑客方式,除非它涉及修改外部依赖项的代码。
如果有用的话:我正在运行Angular 1.2.0。关键是,你的
应用程序模块所依赖的任何模块也需要是延迟加载模块。这是因为angular用于其$injector服务的提供程序和实例缓存是私有的,并且在初始化完成后,它们不公开注册新模块的方法
因此,“黑客”的方法是编辑您希望延迟加载的每个模块,以要求延迟加载模块对象(在您链接的示例中,该模块位于文件“appModules.js”中),然后编辑每个控制器、指令、工厂等调用,改为使用app.lazy.{same call}
之后,您可以通过查看应用程序路由是如何延迟加载的(appRoutes.js文件显示了如何执行此操作),继续关注您链接到的示例项目
不太确定这是否有用,但祝你好运。注意:使用Nikos Paraskevopoulos的解决方案,因为它更可靠(我正在使用它),并且有更多的例子。
好的,我终于找到了如何通过简单的帮助实现这一点
正如我在我的问题中所说,这已经成为一种非常令人讨厌的方式。它包括在应用程序模块的上下文中应用依赖模块的\u invokeQueue
数组中的每个函数
它是这样的(请在ModuleXtender功能中多加注意):
完成后,例如,我只需要执行以下操作:
app.extend( "ui.codemirror" ); // ui.codemirror module will now be available in my application
app.controller( "FirstController", [ ..., function() { });
一段时间以来,我一直在尝试混合requirejs+Angular。到目前为止,我在Github()中发布了一个小项目,因为范围对于内联代码或fiddle来说太大了。该项目展示了以下几点:
- AngularJS模块是延迟加载的
- 指令也可以延迟加载
- 有一个“模块”发现和元数据机制(请参阅我的另一个宠物项目:)
- 应用程序自动拆分为捆绑包(即使用r.js works构建)
如何做到:
- 提供程序(例如,
$controllerProvider
,$compileProvider
)是从config
函数(我第一次看到的技术)中捕获的
- 引导后,
angular
被我们自己的包装器所取代,该包装器可以处理延迟加载的模块
- 喷油器被捕获并作为承诺提供
- AMD模块可以转换为角度模块
这个实现满足了您的需求:它可以延迟加载角度模块(至少是我使用的ng网格),绝对是黑客的:),并且不修改外部库
欢迎发表评论/意见
(编辑)此解决方案与其他解决方案的区别在于它不进行动态require()
调用,因此可以使用r.js(以及我的require lazy项目)构建。除此之外,这些想法在不同的解决方案中或多或少是趋同的
祝大家好运 现有的延迟加载技术的问题在于,它们可以完成我想自己做的事情
例如,使用requirejs,我只想调用:
require(['tinymce', function() {
// here I would like to just have tinymce module loaded and working
});
然而,它不是这样工作的。为什么?据我所知,AngularJS只是将模块标记为“将在将来加载”,例如,如果我稍等片刻,它就会工作——我将能够使用它。所以在上面的函数中,我想调用一些函数,比如loadPendingModules()
在我的项目中,我创建了简单的提供者(“lazyLoad”),它只做这件事,其他什么都不做,所以现在,如果我需要完全加载某个模块,我可以执行以下操作:
myApp.controller('myController', ['$scope', 'lazyLoad', function($scope, lazyLoad) {
// ........
$scope.onMyButtonClicked = function() {
require(['tinymce', function() {
lazyLoad.loadModules();
// and here I can work with the modules as they are completely loaded
}]);
};
// ........
});
以下是指向源文件(MPL许可证)的链接:
有一个指令可以做到这一点:
例如:
<div load-on-demand="'module_name'"></div>
我将向您发送示例代码。这对我来说很好。因此,请检查以下内容:
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
});
}])
var myapp=angular.module('myapp',['ngRoute']);
/*模块创建*/
var app=angular.module('app',['ngRoute']);
app.config(['$routeProvider','$controllerProvider',函数($routeProvider,$controllerProvider){
app.register={
控制器:$controllerProvider.register,
//指令:$compileProvider.directive,
//过滤器:$filterProvider.register,
//工厂:$provide.factory,
//服务:$provide.service
};
//因此,我在运行模块配置时保留了一个引用
功能寄存器控制器(模块名称、控制器名称){
//在这里,我无法直接获取控制器函数,因此
//需要循环通过模块的_invokeQueue来获取它
var queue=angular.module(moduleName)。\u invokeQueue;
对于(变量i=0;ivar 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
});
}])
<body ng-app="app">
<div class="container example">
<!--ng-controller="testController"-->
<h3>Hello</h3>
<table>
<tr>
<td><a href="#/first">First Page </a></td>
<td><a href="#/second">Second Page</a></td>
</tr>
</table>
<div id="ng-view" class="wrapper_inside" ng-view>
</div>
<div class="shubham">
</div>
</div>