开发一个带有动态模块集的AngularJS应用
Developing an AngularJS app with dynamic set of modules
我有一个具有复杂布局的应用程序,用户可以在其中放置(拖放)小部件(通过从预定义的100多个小部件中选择),其中每个小部件都是一个自定义实现,以特定的方式显示一组数据(使用REST调用获取)。我已经阅读了大量的博客文章,stackoverflow问题和AngularJS官方文档,但我不知道我应该如何设计我的应用程序来处理这些需求。看看演示应用程序,有一个单一的模块(ng-app),当在。js文件中构建它时,依赖模块被声明为它的依赖项,但是我有一大组小部件,不知何妨,不建议在那里描述它们。我需要你对以下问题的建议:
- 我应该如何设计我的应用程序和小部件-我应该有一个单独的AngularJS模块或每个小部件应该是一个指令到主模块? 如果我把我的小部件设计成指令,有没有办法在指令中定义依赖关系?也就是说,我的指令使用ng日历在其实施?
- 如果我设计每个小部件作为一个单独的模块,有没有一种方法来动态添加小部件模块作为一个依赖于主模块?
- 我应该如何设计控制器-一个控制器每个小部件可能?
- 如果我在视图中有多个相同类型的小部件,我应该如何分离状态(范围)? 有没有用AngularJS设计可重用小部件的最佳实践?
编辑
有用的参考资料:
- ocLazyLoad - AngularJS的惰性加载库
- 种子项目-模块+延迟加载路由更改(ES6, systemjs, ocLazyLoad) AngularJS中的延迟加载
- 用AngularJS和RequireJS动态加载控制器和视图
- 在应用启动后用RequireJS加载AngularJS组件 在GitHub上延迟加载AngularJS资源的演示项目
- 按需加载项目
- 仅在需要时动态注入模块
- 大型AngularJS和JavaScript应用程序中的代码组织
这些只是一般的建议。
我应该如何设计我的应用程序和小部件-我应该有一个单独的AngularJS模块或每个小部件应该是一个指令到主模块?
你说的是数百个小部件,把它们分成几个模块似乎很自然。有些小部件可能比其他小部件具有更多的共同点。有些可能非常通用,适合其他项目,有些则更具体。
如果我把小部件设计成指令,有没有办法在指令中定义依赖关系?也就是说,我的指令使用ng日历在其实施?
对其他模块的依赖是在模块级别上完成的,但如果模块A
依赖模块B
, A
和B
都依赖模块C
,则没有问题。在Angular中,指令是创建小部件的自然选择。如果一个指令依赖于另一个指令,你要么在同一个模块中定义它们,要么在模块级别上创建依赖。
如果我设计每个小部件作为一个单独的模块,有没有一种方法来动态添加小部件模块作为一个依赖到主模块?
我不知道你为什么要做这件事,我也不知道怎么做。指令和服务在Angular中使用之前不会被初始化。如果你有一个庞大的指令库(小部件),并且知道你可能会使用其中的一些,但不是全部——但你不知道哪些会在应用程序初始化时被使用,你可以在模块加载后"延迟加载"你的指令。我在这里创建了一个示例
这样做的好处是,即使你有很多代码,你也可以让你的应用程序快速加载,因为你不必在需要它们之前加载脚本。缺点是在第一次加载新指令时可能会有相当大的延迟。
我应该如何设计控制器-一个控制器每个小部件可能?
小部件可能需要自己的控制器。控制器通常应该很小,如果它们变大,你可以考虑是否有任何功能更适合服务。
如果我在视图中有多个相同类型的小部件,我应该如何分离状态(范围)?
需要作用域变量的小部件毫无疑问应该有自己独立的作用域(指令配置中的scope:{ ... }
)。
有没有用AngularJS设计可重用小部件的最佳实践?
隔离范围,将依赖关系保持在必要的最低限度。参见Misko关于Angular最佳实践的视频
Brian Ford也写了一篇关于用Angular编写一个庞大应用的文章
这个问题对我来说也很重要。AngularJS主页上有一些例子(你可以叫它们widgets),所以我浏览了它们的源代码,试图看看它们是如何区分widget的。
首先,它们从不声明"ng-app"属性。他们使用
function bootstrap() {
if (window.prettyPrint && window.$ && $.fn.popover && angular.bootstrap &&
hasModule('ngLocal.sk') && hasModule('ngLocal.us') && hasModule('homepage') && hasModule('ngResource')) {
$(function(){
angular.bootstrap(document, ['homepage', 'ngLocal.us']);
});
}
}
以确保所有内容都正确加载。这个想法很好,但奇怪的是,他们总是把ng-app属性推给你,然后自己却不使用它。总之,这是他们加载的主页模块与应用程序- http://angularjs.org/js/homepage.js
里面有一个叫appRun的指令
.directive('appRun', function(fetchCode, $templateCache, $browser) {
return {
terminal: true,
link: function(scope, element, attrs) {
var modules = [];
modules.push(function($provide, $locationProvider) {
$provide.value('$templateCache', {
get: function(key) {
var value = $templateCache.get(key);
if (value) {
value = value.replace(/'#'//mg, '/');
}
return value;
}
});
$provide.value('$anchorScroll', angular.noop);
$provide.value('$browser', $browser);
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
});
if (attrs.module) {
modules.push(attrs.module);
}
element.html(fetchCode(attrs.appRun));
element.bind('click', function(event) {
if (event.target.attributes.getNamedItem('ng-click')) {
event.preventDefault();
}
});
angular.bootstrap(element, modules);
}
};
})
我将使用ToDo列表作为示例。对于html,有
<div app-run="todo.html" class="well"></div>
然后在页面底部有
<script type="text/ng-template" id="todo.html">
<h2>Todo</h2>
<div ng-controller="TodoCtrl">
<span>{{remaining()}} of {{todos.length}} remaining</span>
[ <a href="" ng-click="archive()">archive</a> ]
<ul class="unstyled">
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done">
<span class="done-{{todo.done}}">{{todo.text}}</span>
</li>
</ul>
<form ng-submit="addTodo()">
<input type="text" ng-model="todoText" size="30"
placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>
</div>
</script>
还有
<style type="text/css" id="todo.css"> //style stuff here </style>
<script id="todo.js"> //controller stuff here </script>
代码被使用,但是这些脚本中的id属性对于运行应用程序并不重要。这只是用于显示在应用程序左侧的源代码。
基本上,它们有一个名为appRun的指令,它使用函数fetchCode
.factory('fetchCode', function(indent) {
return function get(id, spaces) {
return indent(angular.element(document.getElementById(id)).html(), spaces);
}
})
获取代码。然后使用angular.bootstrap()创建一个新的应用程序。它们也可以通过app-run加载模块。JavaScript项目示例初始化为
<div app-run="project.html" module="project" class="well"></div>
希望这有帮助。我仍然不确定什么是"最好"的技术,但似乎AngularJS主页只是为每个示例/小部件使用一个完全独立的angular应用程序(ng-app)。我想我也会做同样的事情,除了改变fetchCode函数来获取AJAX的东西。
- 有没有比在app.js上绑定模块名称更好的方法来动态加载视图模型和视图以显示模态
- 在混合基本 URL 下动态加载 require.js 模块
- 使用RequireJS从数组动态加载模块
- AMD 模块中的动态导出
- 如何在生产环境中动态加载多个优化的requirejs模块
- Mozilla”;添加“;sdk,简单的pref模块,动态选项(取决于以前选项的选项)
- RequireJS:将插件动态应用于模块id
- 动态加载模块角度
- RequireJS - 动态加载模块
- 将泛型函数动态关联到对象属性时的作用域.(模块模式)
- “错误:命名模块未知”,从动态路径加载反应本机图像
- 具有动态路由和动态依赖性的角度模块化
- 在 Angular 中动态注入依赖模块
- 杜兰达尔多语言应用程序,页面/模块标题作为可观察的,动态更改文档.标题
- 动态安装和加载节点.js模块
- Angular-动态创建一个新模块,并将其注入主应用程序'的依赖关系
- 动态命名的局部变量,用于加载模块
- 动态地将模块添加到我的Angular应用程序中
- RequireJS中的动态require,得到"尚未加载上下文“”的模块名称;错误
- 我如何在JS中动态地要求模块、实例化对象和调用函数