Кращі практики AngularJS для декларування модуля?


115

У моїй програмі оголошено купу кутових модулів. Спочатку я почав оголошувати їх за допомогою синтаксису "прикутий" таким чином:

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){ ... }]);
    ...
})();

Або це навіть має значення для догляду? Просто цікаво дізнатися, що таке "найкращі практики" для декларування модуля. Заздалегідь спасибі.


3
Мені було цікаво те саме про Angular Best Practices
Далорцо

Відповіді:


118

"Найкращий" спосіб оголошення модуля

Оскільки кутовий знаходиться у самій глобальній області, а модулі зберігаються до його змінної, ви можете отримати доступ до модулів за допомогою 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){
      //..
  }])
})();

Інші глобальні змінні не потрібні.

Звичайно, все залежить від уподобань, але я вважаю, що це найкраща практика

  1. вам не доведеться забруднювати глобальну сферу
  2. Ви можете отримати доступ до своїх модулів скрізь і за власним бажанням сортувати їх та їх функції
  3. ви можете використовувати функціональну форму "використовувати строгий";
  4. порядок завантаження файлів не має великого значення

Параметри сортування модулів та файлів

Цей спосіб декларування та доступу до модулів робить вас дуже гнучкими. Ви можете сортувати модулі за типом функції (як описано в іншій відповіді) або маршрутом, наприклад:

/******** 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-функції). Це зіпсує вашу програму і може бути дуже важко виявити.

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

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


7
Вам не потрібно IIFE (Виконання негайно викликаних функцій), так само анонімна функція самостійного виконання
плюс

1
Ти маєш рацію. Вам це потрібно лише тоді, коли ви хочете застосувати функцію-форму "використовувати строгий"; Не шкодить, хоча.
hugo der hungrige

1
У більшості випадків ви також можете помістити 'use strict';всередину свого компонента. module.controller(function () { 'use strict'; ... });
Джексон

Мені подобається реалізація, але мені теж не весело ланцюжок, тому я змішую це з тим, що робить Бетерраба
Мірко

1
при використанні AMD достатньо одного модуля з назвою додаток. Можна виключати модуль AMD, видаляючи оператор вимагати. І нам більше не потрібно реєструвати контролери та служби.
Джеймс

28

Мені подобається керівництво 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);

Хороша відповідь та чудове посилання.
Ellesedil

якщо у мене різні контролери в різних файлах javascript, це не вимагає завантаження більшої кількості файлів, тобто більше звернень до сервера?
Віньєш Субраманійський

Досить легко злити / uglify / перейменувати їх на gulp or gunnt, vignesh, і особисто я люблю gulp.
aqingsao

1
ви забули додати, що всі ці фрагменти повинні бути в IIFE, інакше у вас є функції на зразок "someFactory ()" у всьому світі. Є ймовірність зіткнення імен. (і вам не потрібно IIFE в es6)
ya_dimon

12

Нещодавно у мене також була ця головоломка. Я почав так само, як і ви, використовуючи ланцюговий синтаксис, але з часом це стає непростим для великих проектів. Зазвичай я б створив модуль контролерів, сервісний модуль і так далі в окремих файлах і вставив їх у свій основний модуль програми, знайдений в іншому файлі. Наприклад:

// 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',[...]);

Це я зробив і для файлу служб, не потрібно змінювати головний файл модуля додатка, який ви все-таки будете вводити в нього ті самі модулі.


1
який сенс створювати окремі модулі для служб / директив / контролерів?
Філіп Собчак

2
У великих проектах все може бути важким для пошуку, коли контролери / фільтри / директиви / служби переплетені разом. Це лише один спосіб організувати речі.
meconroy

1
@FilipSobczak Він НЕ створює окремих модулів для служб / директив / контролерів. Швидше, він створив модуль лише один раз, використовуючи angular.module('my-controllers',[]);(Зауважте, що він декларує [] лише один раз для декларування). Він просто повторно використовує це в інших файлах. Відокремлення файлів дозволяє порівняно легко підтримувати проект, особливо великий.
Девнер

8

Ще однією практикою є складання контролерів, директив тощо у власні модулі та введення цих модулів у ваш "основний":

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


Чому ви використовуєте app.controllersinsted з controllersназвою модуля? Чи є якась перевага? Я новачок у Angularjs
sijo vijayan

4

Мені подобається ділити свої файли та свої модулі.

Щось на зразок цього:

app.js

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

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

direktives.js

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

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

service.js

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

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

Я не великий шанувальник "прикутого стилю", тому я вважаю за краще завжди записувати свою змінну.


2
Це було так, як я це робив, але кожен файл services.js або controller.js швидко розвивається у масштабному проекті, зрештою вам потрібно буде розбити кожну службу чи контролер на окремий файл.
meconroy

1
@meconroy Рівно. Коли річ стає все більшою і більшою, я люблю розбивати директиву на більш дрібні модулі і вводити її тоді в "головний" модуль директиви.
Beterraba


0

Для мене ланцюжок є найбільш компактним способом:

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 = ...;
 })
 ;

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.