Bu dokümanın amacı angular ile geliştirilen ve geçerli olan iyi tasarım ve stillerdir. En iyi kullanışlar:
- AngularJS kaynak kodu
- Kaynak kodları ve okuduğum makaleler
- Kendi deneyimlerim
Not 1: Bu stil rehberi hala bir taslak aşamasındadır. Ana amacı tüm kesimlerce kabul edilmesidir.
Not 2: Herhangi bir doküman takip etmeden önce, dokümanın güncel olduğuna dikkat ediniz. Bu doküman en son versiyonu için geçerlidir.
Bu dokümanda genel Javascript geliştirmelerinin ortak kullanımını göremeyeceksiniz. Genel olarak kullanımlar aşağıdadır:
- Google's JavaScript dokümanı
- Mozilla's JavaScript dokümanı
- Douglas Crockford's JavaScript dokümanı
- Airbnb JavaScript dokümanı
AngularJs geliştirmeleri için Google'ın JavaScript dokümanı.
AngularJS Github dokümanı için ProLoser, buradan kontrol edebilirsin.
- Genel
- Modüller
- Kontrolörler
- Direktifler
- Filtreler
- Services
- Şablonlar
- Yönlendirme
- i18n
- Katkı
- Katkı Sağlayanlar
Büyük AngularJS uygulamaları bir çok bileşenden oluşur. En iyi dizin yapısı dosyalama hiyerarşisidir. 2 tane ana yaklaşım:
- Bileşen türü daha öncelikli olacak şekilde bölünmeler ve işlevselliği daha az kullanıma göre yapılandırma.
Dizin yapısı aşağıdaki şekilde görünecektir:
.
├── app
│ ├── app.js
│ ├── controllers
│ │ ├── home
│ │ │ ├── FirstCtrl.js
│ │ │ └── SecondCtrl.js
│ │ └── about
│ │ └── ThirdCtrl.js
│ ├── directives
│ │ ├── home
│ │ │ └── directive1.js
│ │ └── about
│ │ ├── directive2.js
│ │ └── directive3.js
│ ├── filters
│ │ ├── home
│ │ └── about
│ └── services
│ ├── CommonService.js
│ ├── cache
│ │ ├── Cache1.js
│ │ └── Cache2.js
│ └── models
│ ├── Model1.js
│ └── Model2.js
├── partials
├── lib
└── test
- İşlevselliğin ön planda olduğu ve bileşen yapısının daha az yapıda kullanıldığı yapı aşağıdaki gibidir.
Düzen yapısı:
.
├── app
│ ├── app.js
│ ├── common
│ │ ├── controllers
│ │ ├── directives
│ │ ├── filters
│ │ └── services
│ ├── home
│ │ ├── controllers
│ │ │ ├── FirstCtrl.js
│ │ │ └── SecondCtrl.js
│ │ ├── directives
│ │ │ └── directive1.js
│ │ ├── filters
│ │ │ ├── filter1.js
│ │ │ └── filter2.js
│ │ └── services
│ │ ├── service1.js
│ │ └── service2.js
│ └── about
│ ├── controllers
│ │ └── ThirdCtrl.js
│ ├── directives
│ │ ├── directive2.js
│ │ └── directive3.js
│ ├── filters
│ │ └── filter3.js
│ └── services
│ └── service3.js
├── partials
├── lib
└── test
- Dizin yapısı birden çok kelimeden oluşabilir(örn;my-complex-module ),lisp-case sözdizimi kullanın !:
app
├── app.js
└── my-complex-module
├── controllers
├── directives
├── filters
└── services
- Tüm dosyalarınızı verilen yönergelere koyun. (i.e. şablonlar, CSS/SASS dosyaları, JavaScript) tek dosya içerisinde. Eğer böyle bir yaklaşım seçerseniz, proje yaşamı boyunca heryerde bu yaklaşımı kullanabilirsiniz.
app
└── directives
├── directive1
│ ├── directive1.html
│ ├── directive1.js
│ └── directive1.sass
└── directive2
├── directive2.html
├── directive2.js
└── directive2.sass
Bu yaklaşım yukarıdaki iki dizin yapısı ile birleştirilmiştir.
- Unit testlerimiz bulunduğu bileşen ile birlikte olmalıdır. Bu yol ile yaptığımız testleri daha kolay buluruz ve yönetimimiz daha kolay olur. Ayrıca testlerimiz dokümantasyon ve kullanıcı senaryolarını da içermelidir.
services
├── cache
│ ├── cache1.js
│ └── cache1.spec.js
└── models
├── model1.js
└── model1.spec.js
app.js
dosyasında yönlendirme bulunmalıdır.- Her bir JavaScript dosyası sadece tek bir bileşen bulundurmalıdır. Dosya bileşenin adı ile adlandırılmış olmalıdır.
- AngularJS proje yapısı şablonu örnek olarak kullanabilirsiniz; Yeoman, ng-boilerplate.
Conventions about component naming can be found in each component section.
TLDR; Alltaki komutları koyun.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>MyApp</title>
</head>
<body>
<div ng-app="myApp">
<div ng-view></div>
</div>
<script src="angular.js"></script>
<script src="app.js"></script>
</body>
</html>
Basit yapıda tutun ve özelleşmiş direktifleri sonra koyun. Bu yöntem; kodun geliştirmesini ve bakımını daha kolay hale getirir. Ayrıca HTML tarafından daha kolay bulunmasını sağlar.
<form class="frm" ng-submit="login.authenticate()">
<div>
<input class="ipt" type="text" placeholder="name" require ng-model="user.name">
</div>
</form>
Diğer HTML niteliklerini bu dokümanda bulabilirsiniz.
- Watch only the most vital variables. When required to invoke the
$digest
loop explicitly (it should happen only in exceptional cases), invoke it only when required (for example: when using real-time communication, don't cause a$digest
loop in each received message). - For content that is initialized only once and then never changed, use single-time watchers like
bindonce
for older versions of AngularJS or one-time bindings in AngularJS >=1.3.0. - Make the computations in
$watch
as simple as possible. Making heavy and slow computations in a single$watch
will slow down the whole application (the$digest
loop is done in a single thread because of the single-threaded nature of JavaScript). - When watching collections, do not watch them deeply when not strongly required. Better use
$watchCollection
, which performs a shallow check for equility of the result of the watched expression and the previous value of the expression's evaluation. - Set third parameter in
$timeout
function to false to skip the$digest
loop when no watched variables are impacted by the invocation of the$timeout
callback function. - When dealing with big collections, which change rarely, use immutable data structures.
- Kullan:
setTimeout
yerine$timeout
setInterval
yerine$interval
window
yerine$window
$document
yerine$document
$.ajax
yerine$http
window.location
veya$window.location
yerine$location
document.cookie
yerine$cookies
Böylece kod daha test edilebilir hale gelir ve beklenmeyen hataların önüne geçilir. (Örneğin; unutursan $scope.$apply
in setTimeout
).
-
İş akışını bu araçlar ile otomatik hale getirin:
-
Callbacks yerine promise yapısını kullanın. (
$q
) Kodu daha güzel, temiz ve test edilebilir hale getirir. Ve bizi callback yapısından kurtarır. -
Mümkün olduğunca
$http
yerine$resource
kullanın. Soyutlama düzeyinde fazlalılıktan size kurtaracaktır. -
Olası hataları önlemek için AngularJS pre-minifier kullanın. (ng-annotate)
-
Globals kullanmayın. Tüm bağımlılıkları Dependency Injection ile çözümleyin, bu olası bug çözümleri ve testler için kolaylık sağlayacaktır.
-
Kodunuzu
$scope
ile kirletmeyin. Sadece fonksiyon ve değişkenlerde kullanın. Bu kullanılan değişken ve fonksiyonların şablonlarda kullanıldığına dikkat edin. -
Prefer the usage of controllers instead of
ngInit
. The only appropriate use ofngInit
is for aliasing special properties ofngRepeat
. Besides this case, you should use controllers rather thanngInit
to initialize values on a scope. -
Değişkenlerde, methodlarda ve özelliklerde
$
ön ekini kullanmayın. Çünkü bu ön ek AngularJS tarafından ayrılmıştır. -
AngularJS DI yapısıyla bağımlılıkları çözerken,bağımlılıkları türlerine göre sıralayınız.AngularJS tarafından ayağa kaldırılan bağımlılıklar ilk sırada olmalı daha sonra sizin yaptığınız bağımlılıklar gelmelidir. Aşağıda bir örnek görebilirsiniz:
module.factory('Service', function ($rootScope, $timeout, MyCustomDependency1, MyCustomDependency2) {
return {
//Something
};
});
- Modül isimleri lowerCamelCase yapısına uygun olmalıdır. Küçük harf ile başlamalıdır.
b
modülüa
nın bir alt modülü ise, isimlendirmea.b
şekilde olmalıdır.
Modülleri yapısına göre 2 şekilde sıralayabiliriz:
- işlevselliğine göre,
- bileşen türüne göre.
Aslında büyük bir fark yok aralarında, ama ilk yöntem daha temiz bir yapıdır. Bunun yanında, eğer lazy-loading modülü gelirse (şuanda AngularJS yol haritasında yok), uygulama performansını artıracaktır.
- Kontroller tarafında DOM müdahale etmeyin, bu sizin kontroller tarafındanki test etmenizi zor hale getirir ve bazı prensibleri ihlal etmiş olursunuz Separation of Concerns principle. Bunun yerine directive'leri kullanın.
- Controler'ların ismi yaptığı iş ile aynı isimde olmalıdır. (örneğin; shopping cart, homepage, admin panel) ve sonu
Ctrl
ile bitmelidir. Controler'ların ismi UpperCamelCase (HomePageCtrl
,ShoppingCartCtrl
,AdminPanelCtrl
, vb.) yapısında olmalıdır. - Controler'lar global olarak tanımlanmamalıdır. (AngularJS buna izin verse bile, bu kötü bir yaklaşımdır ve global isim alanını kirletir. Kullanmayın!).
- Aşağıda tanımlanan örnek yapısında kullanın:
function MyCtrl(dependency1, dependency2, ..., dependencyn) {
// ...
}
module.controller('MyCtrl', MyCtrl);
In order to prevent problems with minification, you can automatically generate the array definition syntax from the standard one using tools like ng-annotate (and grunt task grunt-ng-annotate).
- If using array definition syntax, use the original names of the controller's dependencies. This will help you produce more readable code:
function MyCtrl(s) {
// ...
}
module.controller('MyCtrl', ['$scope', MyCtrl]);
okunabilirliği daha az:
function MyCtrl($scope) {
// ...
}
module.controller('MyCtrl', ['$scope', MyCtrl]);
This especially applies to a file that has so much code that you'd need to scroll through. This would possibly cause you to forget which variable is tied to which dependency.
- Make the controllers as lean as possible. Abstract commonly used functions into a service.
- Communicate within different controllers using method invocation (possible when a child wants to communicate with its parent) or
$emit
,$broadcast
and$on
methods. The emitted and broadcasted messages should be kept to a minimum. - Make a list of all messages which are passed using
$emit
,$broadcast
and manage it carefully because of name collisions and possible bugs.
Example:
// app.js
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Custom events:
- 'authorization-message' - description of the message
- { user, role, action } - data format
- user - a string, which contains the username
- role - an ID of the role the user has
- action - specific ation the user tries to perform
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- When you need to format data encapsulate the formatting logic into a filter and declare it as dependency:
function myFormat() {
return function () {
// ...
};
}
module.filter('myFormat', myFormat);
function MyCtrl($scope, myFormatFilter) {
// ...
}
module.controller('MyCtrl', MyCtrl);
- In case of nested controllers use "nested scoping" (the
controllerAs
syntax):
app.js
module.config(function ($routeProvider) {
$routeProvider
.when('/route', {
templateUrl: 'partials/template.html',
controller: 'HomeCtrl',
controllerAs: 'home'
});
});
HomeCtrl
function HomeCtrl() {
this.bindingValue = 42;
}
template.html
<div ng-bind="home.bindingValue"></div>
- Direktif isimleri lowerCamelCase yapısına uygun olmalıdır.
- Link fonksiyonunda
$scope
yerinescope
kullanın.In the compile, post/pre link functions you have already defined arguments which will be passed when the function is invoked, you won't be able to change them using DI. This style is also used in AngularJS's source code. - Direktiflerde özel ön ekler kullanın bunun amacı kullandığınız diğer kütüphanelerde isim karışıklığını engeller.Use custom prefixes for your directives to prevent name collisions with third-party libraries.
- Do not use
ng
orui
prefixes since they are reserved for AngularJS and AngularJS UI usage. - DOM manipulations must be done only through directives.
- Create an isolated scope when you develop reusable components.
- Use directives as attributes or elements instead of comments or classes, this will make your code more readable.
- Use
scope.$on('$destroy', fn)
for cleaning up. This is especially useful when you're wrapping third-party plugins as directives. - Do not forget to use
$sce
when you should deal with untrusted content.
- Filtre isimleri lowerCamelCase yapısına uygun olmalıdır.
- Tüm filtrelerin bağımsız olduğuna emin olun. They are called often during the
$digest
loop so creating a slow filter will slow down your app. - Filtreleme işlemlerinde sadece bir iş yapın,ve işler tutarlı olsun. More complex manipulations can be achieved by piping existing filters.
Bu bölümde AngularJs Service yapısınına bakıyoruz.Hangisine bağlı olarak geliştirdiğinin önemi yoktur. (i.e. örnek; provider, .factory
, .service
).
-
Servis isimleri camelCase yapısına uygun olmalıdır.
-
UpperCamelCase (PascalCase) yapısında isimlendirilmelidir, yapıcı fonksiyon örneği kullanılmıştır i.e.:
function MainCtrl($scope, User) { $scope.user = new User('foo', 42); } module.controller('MainCtrl', MainCtrl); function User(name, age) { this.name = name; this.age = age; } module.factory('User', function () { return User; });
-
Diğer tüm servisler için lowerCamelCase kullanın.
-
-
Servis katmanınında tüm işlemleri saklayın.
-
Services representing the domain preferably a
service
instead of afactory
. In this way we can take advantage of the "klassical" inheritance easier:
function Human() {
//body
}
Human.prototype.talk = function () {
return "I'm talking";
};
function Developer() {
//body
}
Developer.prototype = Object.create(Human.prototype);
Developer.prototype.code = function () {
return "I'm coding";
};
myModule.service('Human', Human);
myModule.service('Developer', Developer);
- Session-level önbellekleme yapmak için
$cacheFactory
kullanın. - Eğer kullandığınız servis yapılandırma gerekiyorsa, servis sağlayıcı kullanın ve bunu
config
callback yapılandırın. Aşağıda bir örnek tanımlanmıştır
angular.module('demo', [])
.config(function ($provide) {
$provide.provider('sample', function () {
var foo = 42;
return {
setFoo: function (f) {
foo = f;
},
$get: function () {
return {
foo: foo
};
}
};
});
});
var demo = angular.module('demo');
demo.config(function (sampleProvider) {
sampleProvider.setFoo(41);
});
ng-bind
veyang-cloak
kullanın.Instead of simple{{ }}
to prevent flashing content. //- Html Şablonları içinde karışık ifadeler yazmaktan kaçının.
- Html Şablonların içinde
src
etiketi yerine AngularJS bize sunmuş olduğung-src
etiketini kullanın. - Html Şablonların içinde
href
etiketi yerine AngularJS bize sunmuş olduğung-href
etiketini kullanın. - Scope değişkenlerini string kullanmak yerine
style
özelliği birlikte{{ }}
kullanın ve direktif olarakng-style
kullanın.
<script>
...
$scope.divStyle = {
width: 200,
position: 'relative'
};
...
</script>
<div ng-style="divStyle">my beautifully styled div which will work in IE</div>;
- View gözükmeden önce bağımlılıklarınızı çözmek için
resolve
kullanın. resolve
callback içerisine açık olarak RESTful koymayın.Uygun servislerin içersine birbirden bağımsız olacak şekilde yerleştirin.Böylece önbelleğe izin verme ve separation of concerns principle sağlamış oluruz.
- Angular yeni versiyonu için (>=1.4.0) i18n araçını kullanın, eğer eski versiyonu kullanıyorsanız (<1.4.0) kullanın
angular-translate
.
mgechev | pascalockert | morizotter | ericguirbal | mainyaa | elfinxx |
agnislav | rubystream | lukaszklis | susieyy | cironunes | cavarzan |
guiltry | tornad | jmblog | kuzzmi | dchest | gsamokovarov |
clbn | apetro | valgreens | bitdeli-chef | bradgearon | astalker |
dreame4 | grvcoelho | bargaorobalo | hermankan | jabhishek | jesselpalmer |
vorktanamobay | capaj | jordanyee | nacyot | mariolamacchia | kirstein |
mo-gr | cryptojuice | olov | johnnyghost | sahat | kaneshin |
imaimiami | gitter-badger | thomastuts | grapswiz | coderhaoxin | ntaoo |
kuzmeig1 |
gokhan |