Skip to content

Latest commit

 

History

History
477 lines (380 loc) · 21.7 KB

README-id-id.md

File metadata and controls

477 lines (380 loc) · 21.7 KB

Introduksi

Tujuan dari panduan ini adalah memberikan standar gaya dan cara-cara terbaik menulis kode untuk sebuah aplikasi AngularJS. Cara-cara ini dikumpulkan dari:

  1. Kode sumber AngularJS
  2. Kode-kode atau artikel yang pernah saya baca
  3. Pengalaman saya sendiri

Catatan 1: Panduan ini masih berupa konsep, tujuan utamanya adalah agar dikendalikan oleh komunitas, jadi menyumbangkan waktu anda untuk proyek ini akan sangat dihargai seluruh komunitas.

Catatan 2: Sebelum mengikuti panduan ini, pastikan bahwa panduan ini versi yang terbaru atau sama dengan versi dalam bahasa inggris (bisa anda cek dari waktu commit).

Dalam panduan ini, anda tidak akan menemukan panduan umum untuk menulis kode javascript. Seperti yang bisa anda temukan di:

  1. Panduan menulis kode javascript milik Google
  2. Panduan menulis kode javascript milik Mozilla
  3. Panduan menulis kode javascript milik GitHub
  4. Panduan menulis kode javascript milik Douglas
  5. Panduan menulis kode javascript milik Airbnb

Tapi setidaknya kami merekomendasikan anda untuk mengikuti Panduan menulis kode javascript milik Google.

Di halaman GitHub milik AngularJS ada sebuah wiki yang bagus seputar topik ini, kontribusi dari ProLoser, anda bisa melihatnya di sini.

Daftar isi

Umum

Struktur Direktori

Karena sebuah aplikasi bisa mempunyai banyak komponen, sangat baik untuk membuatnya terstruktur seperti struktur direktori. Ada 2 struktur yang biasa digunakan:

Struktur 1: Membagi menjadi 2 divisi, divisi atas disusun berdasarkan komponen, divisi bawah berdasarkan fungsionalitas.

Dengan cara ini, struktur akan terlihat seperti ini:

.
├── 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

Struktur 2: Membagi menjadi 2 divisi, divisi atas disusun berdasarkan fungsionalitas, divisi bawah berdasarkan komponen.

Dengan cara ini, struktur akan terlihat seperti ini:

.
├── 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

Struktur tambahan: Ketika membuat directives, akan sangat memudahkan apabila anda menempatkan semua file yang berhubungan (seperti: templates, CSS/SASS) di dalam direktori yang sama. Jika anda mengikuti cara ini, anda harus konsisten.

app
└── directives
    ├── directive1
    │   ├── directive1.html
    │   ├── directive1.js
    │   └── directive1.sass
    └── directive2
        ├── directive2.html
        ├── directive2.js
        └── directive2.sass

Struktur tambahan ini bisa dikombinasikan dengan 2 struktur di atas.

Variasi Struktur: Seperti yang digunakan di proyek ng-boilerplate. Di dalam proyek tersebut, setiap unit testing ditempatkan dalam 1 direktori yang sama dengan komponen. Dengan cara tersebut, anda akan menemukannya dengan cepat dan juga bisa digunakan untuk dokumentasi dan cara penggunaan komponen tersebut.

services
├── cache
│   ├── cache1.js
│   └── cache1.spec.js
└── models
    ├── model1.js
    └── model1.spec.js
  • File app.js berisi definisi routing dan konfigurasi.
  • Setiap file javascript, hanya boleh berisi sebuah komponen. File tersebut harus diberi nama sesuai nama komponen.
  • Alternatif lain, gunakan struktur seperti di Yeoman, ng-boilerplate.

Saya sendiri lebih menyukai struktur pertama, karena komponen lebih mudah dicari.

Untuk Aturan standar penamaan komponen bisa ditemukan di panduan tiap bagian.

Markup

TLDR; Letakan semua script di bagian bawah halaman.

<!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>

Buat semuanya simpel dan susun file dari yang sangat umum hingga directive yang spesifik di bagian akhir. Dengan begitu lebih mudah untuk melihat, mencari dan mengubahnya.

<form class="frm" ng-submit="login.authenticate()">
  <div>
    <input class="ipt" type="text" placeholder="name" require ng-model="user.name">
  </div>
</form>

Untuk atribut HTML yang lain, ikuti panduan ini

Optimasi "digest cycle"

  • Hanya 'watch' variabel vital (seperti: ketika menggunakan komunikasi real-time, jangan gunakan $digest loop disetiap pesan yang diterima).
  • Untuk konten yang diinisialisasi sekali dan tidak pernah berubah lagi, gunakan 'single-time watchers' seperti bindonce.
  • Buat komputasi di dalam $watch se-simpel mungkin. Karena komputasi berat atau lambat di sebuah $watch akan memperlambat seluruh aplikasimu.
  • Set false parameter ke 3 di $timeout untuk melewatkan $digest loop ketika tidak ada lagi variabel yang harus di 'watch'.

Lain Lain

  • Gunakan:
    • $timeout daripada setTimeout
    • $interval daripada setInterval
    • $window daripada window
    • $document daripada document
    • $http daripada $.ajax

Ini akan mempermudah testing dan akan mencegah kejadian tidak terduga (seperti, jika anda melewatkan $scope.$apply di setTimeout).

  • Otomatiskan sistem kerja anda dengan tool bantuan seperti:

  • Gunakan promises ($q) daripada callbacks. Ini akan membuat kode anda lebih elegan dan bersih, dan menyelamatkan anda dari 'callback hell'.

  • Gunakan $resource daripada $http jika memungkinkan. Semakin tinggi level abstraksi, akan menyelamatkan anda dari redudansi.

  • Gunakan AngularJS pre-minifier (seperti ngmin atau ng-annotate) untuk mencegah masalah setelah proses minifikasi.

  • Jangan gunakan variabel global. Selalu gunakan Dependency Injection.

  • Jangan kotori $scope. Hanya tambahkan fungsi dan variabel yang benar-benar akan digunakan.

  • Lebih baik inisialisasi variabel di controllers daripada menggunakan ngInit. Hanya gunakan ngInit untuk aliasing di ngRepeat.

  • Jangan gunakan awalan $ untuk nama variabel, properti dan fungsi. Awalan ini digunakan oleh AngularJS.

  • Ketika melakukan Depedency Injection, susun semuanya dimulai dari library AngularJS terlebih dahulu, setelah itu library kustom anda:

module.factory('Service', function ($rootScope, $timeout, MyCustomDependency1, MyCustomDependency2) {
  return {
    //Something
  };
});

Modules

  • Modules harus diberi nama dengan standar 'lowerCamelCase'. Apabila module b adalah submodule dari module a, maka anda bisa menumpuknya dengan namespace seperti: a.b.

Ada 2 struktur umum untuk modul:

  1. Dari fungsionalitas
  2. Dari tipe komponen

Saat ini 2 struktur di atas tidak terlalu berbeda, tapi yang pertama lebih terlihat bersih. Namun, apabila module 'lazy-loading' sudah diimplementasikan (walaupun saat ini module tersebut tidak ada dalam roadmap tim AngularJS), struktur pertama dapat menambah performa aplikasi anda.

Controllers

  • Jangan memanipulasi DOM dari controller, akan membuat controller anda sulit di tes dan melawan prinsip Separation of Concerns. Lebih baik gunakan directive.
  • Untuk penamaan controller gunakan standar 'UpperCamelCase' dan harus sesuai dengan fungsionalitasnya (seperti: shopping cart, homepage, admin panel) dan diakhiri dengan Ctrl (HomePageCtrl, ShoppingCartCtrl, AdminPanelCtrl, dll.).
  • Controller tidak boleh didefinisikan secara global (meskipun AngularJS mengijinkan hal ini, namun sangatlah tidak baik mengotori namespace global).
  • Gunakan syntax array untuk definisi controller:
module.controller('MyCtrl', ['dependency1', 'dependency2', ..., 'dependencyN', function (dependency1, dependency2, ..., dependencyN) {
  //...body
}]);

Gunakan cara definisi seperti ini untuk menghindarkan masalah minifikasi. Anda dapat secara otomatis menghasilkan definisi seperti di atas dengan menggunakan tool seperti ng-annotate (dan grunt task grunt-ng-annotate).

  • Gunakan nama asli dari Dependency Injection, ini akan memudahkanmu membaca kode:
module.controller('MyCtrl', ['$scope', function (s) {
  //...body
}]);

Akan lebih susah dimengerti daripada:

module.controller('MyCtrl', ['$scope', function ($scope) {
  //...body
}]);

Hal ini akan sangat berguna ketika file yang anda baca cukup panjang.

  • Buat controller sesimpel mungkin dan abstraksikan semua logika bisnis ke dalam service.
  • Komunikasi dengan controller yang berbeda menggunakan method invocation (memungkinkan ketika child controller ingin berkomunikasi dengan parent controller) atau $emit, $broadcast dan $on. Pesan yang disebarkan harus seminimum mungkin.
  • Buatlah daftar semua pesan yang digunakan $emit, $broadcast dan atur secara hati-hati untuk menghindari nama yang sama.
  • Ketika anda ingin mengubah format tampilan data, gunakan filter:
module.filter('myFormat', function () {
  return function () {
    //body...
  };
});

module.controller('MyCtrl', ['$scope', 'myFormatFilter', function ($scope, myFormatFilter) {
  //body...
}]);
  • Untuk controller yang bertumpuk, gunakan "nested scoping" dengan controllerAs:

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>

Directives

  • Gunakan standar penamaan 'lowerCamelCase'.
  • Gunakan scope daripada $scope di dalam link function. Pada saat proses kompilasi, post/pre link function yang telah didefinisikan dengan argumen, akan diberikan ketika fungsi tersebut dipanggil, anda tidak akan dapat mengubahnya dengan Dependency Injection. Cara ini juga digunakan di kode sumber AngularJS.
  • Gunakan awalan yang berbeda untuk directive, untuk mencegah error karena penggunaan nama yang sama dengan third-party library.
  • Jangan gunakan awalan ng atau ui karena telah digunakan untuk AngularJS dan AngularJS UI.
  • Manipulasi DOM hanya dilakukan di dalam directive.
  • Usahakan scope harus terisolasi ketika membuat komponen yang bisa digunakan kembali.
  • Gunakan directive di atribut atau elemen daripada di komentar atau class, ini akan membuat kode lebih mudah dibaca.
  • Gunakan $scope.$on('$destroy', fn) untuk membersihkan. Sangat berguna terutama ketika anda menggunakan third-party plugin sebagai directive.
  • Jangan lupa gunakan $sce untuk konten yang tidak dapat dipercaya.

Filters

  • Gunakan standar penamaan 'lowerCamelCase'.
  • Buat filter anda se-ringan mungkin karena sering dipanggil selama $digest loop.
  • Fokus lakukan 1 hal saja untuk setiap filter. Untuk manipulasi lebih kompleks, lebih baik menggabungkan beberapa filter sekaligus.

Services

Bagian ini adalah informasi tentang komponen service secara umum di AngularJS dan tidak spesifik tentang (provider, .factory atau .service), kecuali ditegaskan demikian.

  • Gunakan standar penamaan 'camelCase'.

    • UpperCamelCase (PascalCase) untuk nama service apabila digunakan sebagai konstruktor, seperti:

      module.controller('MainCtrl', function ($scope, User) {
        $scope.user = new User('foo', 42);
      });
      
      module.factory('User', function () {
        return function User(name, age) {
          this.name = name;
          this.age = age;
        };
      });
    • lowerCamelCase untuk semua service yang lain.

  • Enkapsulasikan semua logika bisnis di dalam service.

  • Service yang merepresentasikan domain lebih baik adalah service daripada factory. Dengan begitu kita dapat lebih mudah mendapatkan keuntungan dari "klassical" inheritance:

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);
  • Untuk cache pada level session gunakan $cacheFactory. Ini harus digunakan untuk meng-cache hasil dari request atau komputasi yang berat.
  • Jika sebuah service membutuhkan konfigurasi, maka definisikan service tersebut sebagai provider dan konfigurasikan service itu di dalam config callback seperti:
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);
});

Templates

  • Gunakan ng-bind atau ng-cloak daripada {{ }} untuk mencegah konten yang berkedip (flashing content).
  • Hindari menulis ekspresi yang kompleks di dalam template.
  • Gunakan ng-src dan {{ }} daripada hanya src
  • Gunakan ng-href daripada src dan {{ }}
  • Gunakan ng-style daripada style dan {{ }}
<script>
...
$scope.divStyle = {
  width: 200,
  position: 'relative'
};
...
</script>

<div ng-style="divStyle">my beautifully styled div which will work in IE</div>;

Routing

  • Gunakan resolve untuk resolve dependencies sebelum view ditampilkan.

Testing

TBD

Sampai bagian ini selesai, anda bisa menggunakan panduan ini terlebih dahulu.

Kontribusi

Karena panduan ini dibuat oleh komunitas, kontribusi sangatlah dihargai. Contohnya, anda dapat berkontribusi dengan memperluas bagian testing atau dengan menerjemahkan panduan ini ke dalam bahasa anda.

Kontributor

mgechev pascalockert mainyaa rubystream lukaszklis
mgechev pascalockert mainyaa rubystream lukaszklis
cironunes cavarzan tornad jmblog bargaorobalo
cironunes cavarzan tornad jmblog bargaorobalo
astalker valgreens bitdeli-chef dchest gsamokovarov
astalker valgreens bitdeli-chef dchest gsamokovarov
ntaoo hermankan jesselpalmer capaj jordanyee
ntaoo hermankan jesselpalmer capaj jordanyee
nacyot kirstein mo-gr cryptojuice olov
nacyot kirstein mo-gr cryptojuice olov
vorktanamobay thomastuts grapswiz coderhaoxin dreame4
vorktanamobay thomastuts grapswiz coderhaoxin dreame4
guiltry
guiltry