Оптимальные методы AngularJS для объявления модулей?

У меня есть куча модулей Angular, объявленных в моем приложении. Сначала я начал объявлять их с помощью синтаксиса "цепочка":

angular.module('mymodule', [])
    .controller('myctrl', ['dep1', function(dep1){ ... }])
    .service('myservice', ['dep2', function(dep2){ ... }])
    ... // more here

Но я решил, что читать это было не так просто, поэтому я начал объявлять их с помощью модульной переменной следующим образом:

var mod = angular.module('mymodule', []);

mod.controller('myctrl', ['dep1', function(dep1){ ... }]);

mod.service('myservice', ['dep2', function(dep2){ ... }]);
...

Второй синтаксис кажется мне более читаемым, но моя единственная жалоба заключается в том, что этот синтаксис оставляет переменную mod в глобальной области. Если у меня когда-нибудь будет другая переменная с именем mod, она будет переопределена следующей следующей (и другими проблемами, связанными с глобальными переменными).

Итак, мой вопрос: это лучший способ? Или было бы лучше сделать что-то подобное?:

(function(){
    var mod = angular.module('mymod', []);
    mod.controller('myctrl', ['dep1', function(dep1){ ... }]);
    mod.service('myservice', ['dep2', function(dep2){ ... }]);
    ...
})();

Или это даже достаточно важно, чтобы заботиться? Просто любопытно узнать, что такое "лучшие практики" для декларации модуля. Спасибо заранее.

Ответ 1

Лучший способ объявить модуль

Поскольку angular находится в самой глобальной области и модули сохраняются в своей переменной, вы можете получать доступ к модулям через angular.module('mymod'):

// one file
// NOTE: the immediately invoked function expression 
// is used to exemplify different files and is not required
(function(){
   // declaring the module in one file / anonymous function
   // (only pass a second parameter THIS ONE TIME as a redecleration creates bugs
   // which are very hard to dedect)
   angular.module('mymod', []);
})();


// another file and/or another anonymous function
(function(){   
 // using the function form of use-strict...
 "use strict";
  // accessing the module in another. 
  // this can be done by calling angular.module without the []-brackets
  angular.module('mymod')
    .controller('myctrl', ['dep1', function(dep1){
      //..
    }])

  // appending another service/controller/filter etc to the same module-call inside the same file
    .service('myservice', ['dep2', function(dep2){ 
    //... 
    }]);

  // you can of course use angular.module('mymod') here as well
  angular.module('mymod').controller('anothermyctrl', ['dep1', function(dep1){
      //..
  }])
})();

Других глобальных переменных не требуется.

Конечно, все зависит от предпочтений, но я думаю, что это своего рода лучшая практика, поскольку

  • вам не нужно загрязнять глобальную область.
  • вы можете получать доступ к своим модулям повсюду и сортировать их и их функции в разные файлы по своему усмотрению.
  • вы можете использовать функциональную форму "use strict";
  • порядок загрузки файлов не имеет значения

Параметры для сортировки ваших модулей и файлов

Этот способ декларирования и доступа к модулям делает вас очень гибким. Вы можете сортировать модули с помощью функционального типа (как описано в другом ответе) или по маршруту, например:

/******** sorting by route **********/    
angular.module('home')...
angular.module('another-route')...
angular.module('shared')...

Как вы его сортируете, в конце концов, это вопрос личного вкуса, масштаб и тип проекта. Мне лично нравится группировать все файлы модуля внутри одной и той же папки (упорядоченные в подпапки директив, контроллеров, сервисов и фильтров), включая все разные тестовые файлы, поскольку это делает ваши модули более многоразовыми. Таким образом, в проектах среднего размера я получаю базовый модуль, который включает в себя все основные маршруты и их контроллеры, службы, директивы и более или менее сложные подмодули, когда я думаю, что они могут быть полезны и для других проектов, например

/******** modularizing feature-sets **********/
/controllers
/directives
/filters
/services
/my-map-sub-module
/my-map-sub-module/controllers
/my-map-sub-module/services
app.js
...

angular.module('app', [
  'app.directives',
  'app.filters',
  'app.controllers',
  'app.services',
  'myMapSubModule'
]);

angular.module('myMapSubModule',[
   'myMapSubModule.controllers',
   'myMapSubModule.services',
   // only if they are specific to the module
   'myMapSubModule.directives',
   'myMapSubModule.filters'
]);

Для очень больших проектов я иногда группирую модули по маршрутам, как описано выше, или некоторыми выбранными основными маршрутами или даже комбинацией маршрутов и некоторых выбранных компонентов, но это действительно зависит.

EDIT: Просто потому, что это связано, и я снова столкнулся с этим: Позаботьтесь о том, чтобы создать модуль только один раз (добавив второй параметр в функцию angular.module-function). Это испортит ваше приложение и может быть очень сложно обнаружить.

2015 EDIT для модулей сортировки: Спустя полтора года из angular -experience позже я могу добавить, что преимущества использования именованных модулей в вашем приложении несколько ограничены, поскольку AMD по-прежнему не очень хорошо работает с angular, а службы, директивы и фильтры глобально доступный внутри контекста angular в любом случае (как показано здесь). По-прежнему существует семантическое и структурное преимущество, хотя и может быть полезно включить/исключить модуль с одной строкой кода, прокомментированной или отсутствующей.

Он также почти никогда не имеет смысла разделять подмодули по типу (например, "myMapSubModule.controllers" ), поскольку они обычно зависят друг от друга.

Ответ 2

Мне нравится angular-styleguide от Johnpapa, и вот некоторые правила, связанные с этим вопросом:

Правило: Именованные и анонимные функции

Избегайте использования анонимных функций:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', function() { })

Вместо этого используйте именованные функции:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', Dashboard);

function Dashboard() { }

Как говорит автор: This produces more readable code, is much easier to debug, and reduces the amount of nested callback code.

Правило: укажите 1 компонент на файл.

Избегайте нескольких компонентов в одном файле:

angular
  .module('app', ['ngRoute'])
  .controller('SomeController', SomeController)
  .factory('someFactory', someFactory);

function SomeController() { }

function someFactory() { }

Intead, используйте один файл для определения модуля:

// app.module.js
angular
  .module('app', ['ngRoute']);

один файл просто использует модуль для определения компонента

// someController.js
angular
  .module('app')
  .controller('SomeController', SomeController);

function SomeController() { }

и еще один файл для определения другого компонента

// someFactory.js
angular
  .module('app')
  .factory('someFactory', someFactory);

function someFactory() { }

Конечно, существует множество других правил для модулей, контроллеров и сервисов, которые весьма полезны и заслуживают внимания.

И благодаря комментарию ya_dimon, вышеуказанный код должен быть завернут в IIFE, например:

(function (window, angular) {
  angular.module('app')
   .controller('Dashboard', function () { });
})(window, window.angular);

Ответ 3

У меня недавно была эта головоломка. Я начал работать так же, как вы, используя цепочку синтаксиса, но в конечном итоге он становится громоздким с крупными проектами. Обычно я создавал модуль контроллеров, модуль служб и т.д. В отдельных файлах и вставлял их в свой основной прикладной модуль, находящийся в другом файле. Например:

// My Controllers File
angular.module('my-controllers',[])
    .controller('oneCtrl',[...])
    .controller('twoCtrl',[...]);

// My Services File
angular.module('my-services',[])
    .factory('oneSrc',[...])
    .facotry('twoSrc',[...]);

// My Directives File
angular.module('my-directives',[])
    .directive('oneDrct',[...])
    .directive('twoDrct',[...]);

// My Main Application File
angular.module('my-app',['my-controllers','my-services','my-directives',...]);

Но каждый из этих файлов приближался к большому по мере роста проекта. Поэтому я решил разбить их на отдельные файлы на основе каждого контроллера или службы. Я обнаружил, что использование angular.module('mod-name'). без массива инъекций - вот что вам нужно для этого. Объявление глобальной переменной в одном файле и ожидание ее доступности в другом просто не работает или может иметь неожиданные результаты.

Короче, мое приложение выглядело примерно так:

// Main Controller File
angular.module('my-controllers',[]);

// Controller One File
angular.module('my-controllers').controller('oneCtrl',[...]);

//Controller Two File
angular.module('my-controllers').controller('twoCtrl',[...]);

Я сделал это и с файлом служб, не нужно менять основной файл модуля приложения, в который вы все равно будете вводить те же модули.

Ответ 4

Еще одна практика заключается в том, чтобы заполнять контроллеры, директивы и т.д. в своих собственных модулях и вставлять эти модули в ваш "основной":

angular.module('app.controllers', [])
  .controller('controller1', ['$scope', function (scope) {
    scope.name = "USER!";
  }]);

angular.module('app.directives', [])
  .directive('myDirective', [function () {
    return {
      restrict: 'A',
      template: '<div>my directive!</div>'
    }
  }]);

angular.module('app', [
  'app.controllers',
  'app.directives'
]);

В глобальной области ничего не осталось.

http://plnkr.co/edit/EtzzPRyxWT1MkhK7KcLo?p=preview

Ответ 5

Мне нравится делиться моими файлами и моими модулями.

Что-то вроде этого:

app.js

var myApp = angular.module('myApp', ['myApp.controllers', 'myApp.directives', 'myApp.services']);

myApp.config(['$routeProvider', function($routeProvider) {
    /* routes configs */
    $routeProvider.when(/*...*/);
}]);

directives.js

var myDirectives = angular.module('myApp.directives', []);

myDirectives.directive( /* ... */ );

service.js

var myServices = angular.module('myApp.services', []);

myServices.factory( /* ... */ );

Я не большой поклонник "цепного стиля", поэтому я предпочитаю всегда записывать свою переменную.

Ответ 6

Для меня цепочка является самым компактным способом:

angular.module("mod1",["mod1.submod1"])

 .value("myValues", {
   ...
 })

 .factory("myFactory", function(myValues){
   ...
 })

 .controller("MainCtrl", function($scope){

   // when using "Ctrl as" syntax
   var MC = this;
   MC.data = ...;
 })
 ;

Таким образом, я могу легко перемещать компоненты между модулями, никогда не нужно дважды объявлять один и тот же модуль, никогда не нуждаясь в глобальных переменных.

И если файл слишком длинный, решение прост - разделите на два файла, каждый из которых объявит свой собственный модуль наверху. Для большей прозрачности я пытаюсь сохранить один уникальный модуль для каждого файла и называть его похожим на полный путь к файлу. Таким образом, мне также не нужно писать модуль без [], который является общей точкой боли.