#Увод
Циљ овог "style guide" водича је да се представи сет најбољих пракси и смерница за једну AngularJS апликацију. Ове најбоље праксе су прикупљене од:
- AngularJS ижворног кода
- Изворног кода или чланака које сам прочитао
- Личног искуства
Нота: ово је још увек радна верзија, њен главни циљ је да буде "community-driven" зато ће испуњавање празнина бити веома цењено од стране целе заједнице.
У овом водичу нећете наћи уобичајене препоруке за JavaScript програмирање. Такве се могу наћи на:
- Google's JavaScript style guide
- Mozilla's JavaScript style guide
- GitHub's JavaScript style guide
- Douglas Crockford's JavaScript style guide
За AngularJS развој препоручен је Google's JavaScript style guide.
На AngularJS's GitHub wiki-у постоји слична секција од ProLoser, možete je naći na here.
#Садржај
#Уопштено
Како велике AngularJS апликације имају много компоненти најбоље је да се исте организују у структури директоријума. Постоје два приступа:
- Креирање примарног груписања према типу компоненте а затиим секундарно груписање према функционалности.
У овом случају структура директоријума би изгледала овако:
.
├── app
│ ├── app.js
│ ├── controllers
│ │ ├── page1
│ │ │ ├── FirstCtrl.js
│ │ │ └── SecondCtrl.js
│ │ └── page2
│ │ └── ThirdCtrl.js
│ ├── directives
│ │ ├── page1
│ │ │ └── directive1.js
│ │ └── page2
│ │ ├── directive2.js
│ │ └── directive3.js
│ ├── filters
│ │ ├── page1
│ │ └── page2
│ └── services
│ ├── CommonService.js
│ ├── cache
│ │ ├── Cache1.js
│ │ └── Cache2.js
│ └── models
│ ├── Model1.js
│ └── Model2.js
├── lib
└── test
- Креиранје примарног груписања према функционалнисти а затим секундарно груписање према типу компоненте.
Овде је њен респоред:
.
├── app
│ ├── app.js
│ ├── common
│ │ ├── controllers
│ │ ├── directives
│ │ ├── filters
│ │ └── services
│ ├── page1
│ │ ├── controllers
│ │ │ ├── FirstCtrl.js
│ │ │ └── SecondCtrl.js
│ │ ├── directives
│ │ │ └── directive1.js
│ │ ├── filters
│ │ │ ├── filter1.js
│ │ │ └── filter2.js
│ │ └── services
│ │ ├── service1.js
│ │ └── service2.js
│ └── page2
│ ├── controllers
│ │ └── ThirdCtrl.js
│ ├── directives
│ │ ├── directive2.js
│ │ └── directive3.js
│ ├── filters
│ │ └── filter3.js
│ └── services
│ └── service3.js
├── lib
└── test
-
Када креирате директиву може бити корисно да се ставе све повезане датотеке са датом директивом (н.п. шаблони, CSS/SASS датотеке, JavaScript) у један директоријум. Ако изаберете овај стил будите козистентни и користите га свуда у вашем пројекту.
app └── directives ├── directive1 │ ├── directive1.html │ ├── directive1.js │ └── directive1.sass └── directive2 ├── directive2.html ├── directive2.js └── directive2.sass
Овај приступ се може комбиновати са обе верзије структуре директоријума.
-
Још једна блага варијација на обе структуре директоријума је она коришћена у ng-boilerplate. У њој "unit" тестови за дату компоненту се налазе з истом директоријуму као и сама компонента. На овај начин када направите неку промену у датој компоненти лакше је наћи одговарајуће тестове, тестови такође служе као документација и приказују "uses cases".
services ├── cache │ ├── cache1.js │ └── cache1.spec.js └── models ├── model1.js └── model1.spec.js
-
Датотека
app.js
садржи дефиницију рута, конфигурацију и/или "manual bootstrap" (уколико је наопходан). -
Свака JavaScript датотека требало би да садржи само једну компоненту. Датотека би требало да буде именована према имену компоненте.
-
Користи шаблон структуре Angular пројекта као Yeoman, ng-boilerplate.
Ја више преферирам прву структуру јер омогућава лакше пробналажење уобичајених компоненти.
Конвенције око именовања компоненти се могу наћи у свакој секцији која описује дату компоненту.
- Посматрај само најзначајније промењиве (на пример: када се користи "real-time" комуникације, не позивај петљу обраде у свакој примљеној поруци).
- Прави прорачуне у
$watch
што је могуће једноставнијим. постављање захтевне и споре калкулације у једном$watch
ће успорити целокупну апликацију ($digest петља се извршава у једној нити из разлога "single-threaded" природе JavaScript-а).
- Користи:
$timeout
уместоsetTimeout
$window
уместоwindow
$document
уместоdocument
$http
уместо$.ajax
Ово ће учинити тестирање много лакшим а у неким случајевима и предупредити неочекивано понашање (на пример, ако сте пропустили $scope.$apply
у setTimeout
).
-
Аутоматизујте ваш процес рада користећи алате као штоп су:
-
Користите "promises" (
$q
) уместо "callbacks". Ово ће учинити да ваш код изгледа елегантније, и сачуваће вас од "callback" пакла. -
Користите
$resource
уместо$http
кад год је могуће. Виши ниво абстракције спашава вас од непотребног вишка. -
Користите AngularJS "pre-minifier" (like ngmin или ng-annotate) као превенцију проблема после "minification".
-
Не користите глобалне промењиве. Разрешите све зависности користећи "Dependency Injection".
-
Не загађујте ваш
$scope
. Додајте смо оне функције или промењиве које се користе унутар датог шаблона. -
Користите контролере уместо
ngInit
.
#Модули
Постоје два уобичајена начина да се структуирају модули:
- Према функционалности
- Према типу компоненте
Тренутно нема веће разлике, али први начин изгледа уредније. Такође, ако "lazy-loading" модули су имплементирани (тренутно нису у AngularJS плану развоја), то ће побољшати перформансе апликације.
#Контролери
-
Немењајте DOM у вашим контролеримаu. Уместо тога користите директиве.
-
Именовање контролера се врши према његовој функционалности (на пример: shopping cart, homepage, admin panel) и додатке
Ctrl
на крају имена. Имена контролера су записана у "UpperCamelCase" формату (HomePageCtrl
,ShoppingCartCtrl
,AdminPanelCtrl
, итд.). -
Контролери не би требало да буду дефинисани као глобални (без обзира што AngularJS то дозвољаве, лоша је пракса да се загади глобални "namespace").
-
Користи синтаксу низа з дефиницији контролера:
module.controller('MyCtrl', ['dependency1', 'dependency2', ..., 'dependencyn', function (dependency1, dependency2, ..., dependencyn) { //...body }]);
Коришћење овог типа дефиниција избегава проблеме са "minification". Можете аутоматски генерисати низ дефиниција од једне стандардне користећи алате као што су ng-annotate (и grunt задатак grunt-ng-annotate).
-
Користите оригиналне називе зависности контролера. Ово ће вам помоћи да произведете читљивији код:
module.controller('MyCtrl', ['$scope', function (s) { //...body }]);
је мање читљиво од:
module.controller('MyCtrl', ['$scope', function ($scope) {
//...body
}]);
Ово је посебно примењиво да датотеку која има толико кода да ћете морати да се вертикално крећете кроз исти. Ово ће највероватније довести до тога да заборавите која је промењива везана за коју зависност.
-
Креирајте што је могуће "тање" контролере. Абстракујте често коришћене функције у сервис.
-
комуницирајте унутар различитих контролера коришћењем позивање метода (когуће када деца желе да комуницирају са родитељима) или
$emit
,$broadcast
i$on
методе. "Emitted" и "broadcasted" поруке треба држати на минимуму. -
Направите листу свих порука које се преносе коришћењем
$emit
,$broadcast
и пажљиво их одржавајте из разлога колизије назива и могућих грешака. -
Када је потребно да форматирате податке енкапсулирајте логику форматирања унутар филтера и декларишите их као зависности:
module.filter('myFormat', function () { return function () { //body... }; }); module.controller('MyCtrl', ['$scope', 'myFormatFilter', function ($scope, myFormatFilter) { //body... }]);
#Директиве
- Именујте своје директиве користећи "lowerCamelCase"
- Користите
scope
уместо$scope
у вашој "link" функцији. у "compile", пост/пре "link" функцијама већ сте дефинисали аргументе који це бити прослеђени приликом позива функције, нећете моћи да их промените користећи "DI" (Dependency Injection). Овај стил је такође коришћен унутар AngularJS изворног кода. - Користите "custom" префиксе за ваше директиве да би спречили колизију имена са туђим бибљотекама.
- Немојте користити
ng
илиui
префиксе јер су ови резервисани за AngularJS и AngularJS UI употребу. - DOM манипулације морају бити извршене само кроз директиве.
- Креирајте изоловано подручје када развијате компоненте за вишеструку употребу.
#Филтери
- Именујте ваше филтере користећи "lowerCamelCase"
- Креирајте ваше филтере што је могуће "лакшим". Они се зову често током
$digest
петље па креирање спорих филтера ће успорити вашу апликацију.
#Сервиси
- Користите "camelCase (lower or upper)" за називе ваших сервиса.
- енкапсулирајте бизнис логику унутар сервиса.
- Сервиси који уоквирују бизнис логику су пожељно
service
уместоfactory
- За "session-level" кеш можете користити
$cacheFactory
. Ово би требало користити за кеширање резултата захтева или комплексних прорачуна.
#Шаблони
-
Користите
ng-bind
илиng-cloak
уместо простог{{ }}
да би спречили трептање садржаја. -
Избегавајте писање комплексног кода унутар шаблона.
-
Када је потребно да динамички поставите
src
слике користитеng-src
уместоsrc
са{{}}
шаблоном. -
Уместо коришћења "scope" промењиве као текст и користити га заједно са
style
атрибутом са atributom и{{ }}
, користите директивуng-style
са "object-like" параметрима и "scope" промењиве као вредности:... $scope.divStyle = { width: 200, position: 'relative' }; ... <div ng-style="divStyle">my beautifully styled div which will work in IE</div>;
#Рутирање
- Користите
resolve
да разложите све зависности пре него се прикаже "view".