使用一组dynamic模块开发一个AngularJS应用程序

我有一个复杂布局的应用程序,用户可以放置(拖放)小部件(通过从预定义的100多个小部件中进行select),其中每个小部件都是显示一组数据的自定义实现(使用REST调用获取)以特定的方式。 我读过吨的博客post,stackoverflow的问题和官方的AngularJS文档,但我不知道如何devise我的应用程序来处理那里的要求。 看演示应用程序,有一个单独的模块(ng-app),当在.js文件中构build时,相关模块被声明为它的依赖项,但是我有一大套小部件,不知何故,它是不可取的那里。 我需要对以下问题提出build议:

  • 我应该如何devise我的应用程序和小部件 – 我应该有一个单独的AngularJS模块,或者每个小部件应该是主模块的指令?
  • 如果我将小部件devise为指令,是否有方法在指令中定义依赖关系。 也就是说我的指令在其实现中使用ng-calender?
  • 如果我devise每个小部件作为一个单独的模块,是否有办法dynamic添加小部件模块作为依赖主模块?
  • 我应该如何devise控制器 – 每个控件可能有一个控制器?
  • 我应该如何分开状态(范围),如果我在视图中有多个相同types的小部件?
  • 有AngularJSdevise可重用小部件的最佳实践吗?

编辑

有用的参考:

  • ocLazyLoad – AngularJS很好的延迟加载库
  • 种子项目 – 模块+延迟加载路线变化(ES6,systemjs,ocLazyLoad)
  • 在AngularJS中延迟加载
  • 使用AngularJS和RequireJSdynamic加载控制器和视图
  • 在应用程序引导后使用RequireJS加载AngularJS组件
  • 关于在GitHub上延迟加载AngularJS资源的演示项目
  • 按需加载项目
  • 仅在需要时dynamic注入模块
  • 另一个在Angular文章中的延迟加载
  • 大型AngularJS和JavaScript应用程序中的代码组织

这些只是一般的build议。

我应该如何devise我的应用程序和小部件 – 我应该有一个单独的AngularJS模块,或者每个小部件应该是主模块的指令?

你在讨论widgets,把它们分成几个模块似乎很自然。 一些小部件可能比其他小部件有更多的共同点。 有些可能是非常一般的,适合其他项目,其他项目更具体。

如果我将小部件devise为指令,是否有方法在指令中定义依赖关系。 也就是说我的指令在其实现中使用ng-calender?

其他模块的依赖关系在模块级完成,但是如果模块A依赖于模块B并且AB依赖于模块C ,则没有问题。 指令是在Angular中创build小部件的自然select。 如果指令依赖于另一个指令,则可以将它们定义在同一个模块中,或者在模块级别上创build相关性。

如果我devise每个小部件作为一个单独的模块,是否有办法dynamic添加小部件模块作为依赖主模块?

我不知道你为什么要这样做,我不知道该怎么做。 指令和服务在使用Angular之前不会被初始化。 如果你有一个巨大的指令库(widget),并知道你可能会使用其中的一些,但不是所有的 – 但你不知道当应用程序初始化时哪些将被使用,你实际上可以“懒惰加载“您的指令后,您的模块已被加载。 我在这里创build了一个例子

好处就是即使你有很多代码,你也可以让你的应用程序快速加载,因为在你需要之前不需要加载脚本。 缺点是在第一次加载新指令时可能会有相当的延迟。

我应该如何devise控制器 – 每个控件可能有一个控制器?

一个小部件可能需要它自己的控制器。 控制器通常应该很小,如果它们变大,可以考虑是否有任何function更适合于服务。

我应该如何分开状态(范围),如果我在视图中有多个相同types的小部件?

需要作用域variables的小部件无疑应该有自己的独立作用域( scope:{ ... }configuration中的scope:{ ... } )。

有AngularJSdevise可重用小部件的最佳实践吗?

隔离范围,将依赖关系保持在必要的最小值。 参见Misko关于Angular最佳实践的video

Brian Ford还撰写了一篇关于在Angular中编写大型应用程序的文章

这个问题对我来说也很重要。 AngularJS主页上有几个例子(你可以称它们为小部件),所以我去了他们的源代码,试图看看他们如何分开他们的小部件。

首先,他们从不声明“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属性推得太多,甚至不用自己去使用它。 无论如何,这里是他们加载应用程序的主页模块 – 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); } }; }) 

我将以“待办事项”列表为例。 对于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()来创build一个新的应用程序。 他们也可以通过应用程序运行加载模块。 JavaScript项目的例子初始化就像

 <div app-run="project.html" module="project" class="well"></div> 

希望这有助于。 我仍然不确定什么是“最好的”技术,但似乎AngularJS主页为每个示例/小部件简单地使用完全独立的angular度应用程序(ng-app)。 我想我也会这样做,除了改变fetchCode函数来获取AJAX的东西。