#Увод
Циљ овог "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,$broadcasti$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".