Praktik terbaik AngularJS untuk deklarasi modul?


115

Saya memiliki banyak modul Angular yang dideklarasikan di aplikasi saya. Saya awalnya mulai mendeklarasikannya menggunakan sintaks "dirantai" seperti ini:

angular.module('mymodule', [])
    .controller('myctrl', ['dep1', function(dep1){ ... }])
    .service('myservice', ['dep2', function(dep2){ ... }])
    ... // more here

Tetapi saya memutuskan bahwa itu tidak terlalu mudah untuk dibaca, jadi saya mulai mendeklarasikannya menggunakan variabel modul seperti ini:

var mod = angular.module('mymodule', []);

mod.controller('myctrl', ['dep1', function(dep1){ ... }]);

mod.service('myservice', ['dep2', function(dep2){ ... }]);
...

Sintaks kedua tampaknya jauh lebih mudah dibaca oleh saya, tetapi satu-satunya keluhan saya adalah bahwa sintaks ini meninggalkan modvariabel dalam lingkup global. Jika saya pernah memiliki variabel lain bernama mod, itu akan diganti dengan yang berikutnya ini (dan masalah lain yang terkait dengan variabel global).

Jadi pertanyaan saya adalah, apakah ini cara terbaik? Atau lebih baik melakukan hal seperti ini ?:

(function(){
    var mod = angular.module('mymod', []);
    mod.controller('myctrl', ['dep1', function(dep1){ ... }]);
    mod.service('myservice', ['dep2', function(dep2){ ... }]);
    ...
})();

Atau apakah cukup penting untuk peduli? Hanya ingin tahu apa "praktik terbaik" untuk deklarasi modul. Terima kasih sebelumnya.


3
Saya bertanya-tanya hal yang sama tentang Praktik Terbaik Sudut
Dalorzo

Jawaban:


118

Cara 'terbaik' untuk mendeklarasikan modul

Karena angular berada pada cakupan global itu sendiri dan modul disimpan ke variabelnya, Anda dapat mengakses modul melalui 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){
      //..
  }])
})();

Tidak ada variabel global lain yang diperlukan.

Tentu saja itu semua tergantung pada preferensi, tapi saya pikir ini adalah jenis praktik terbaik, sebagai

  1. Anda tidak perlu mencemari ruang lingkup global
  2. Anda dapat mengakses modul Anda di mana saja dan menyortirnya serta fungsinya ke dalam file yang berbeda sesuai keinginan
  3. Anda dapat menggunakan bentuk-fungsi dari "gunakan ketat";
  4. urutan pemuatan file tidak terlalu menjadi masalah

Opsi untuk menyortir modul dan file Anda

Cara mendeklarasikan dan mengakses modul ini membuat Anda sangat fleksibel. Anda dapat mengurutkan modul melalui tipe fungsi (seperti dijelaskan dalam jawaban lain) atau melalui rute, misalnya:

/******** sorting by route **********/    
angular.module('home')...
angular.module('another-route')...
angular.module('shared')...

Bagaimana Anda memilahnya pada akhirnya adalah masalah selera pribadi dan skala serta jenis proyek. Saya pribadi suka mengelompokkan semua file modul di dalam folder yang sama (diurutkan ke dalam sub-folder arahan, pengontrol, layanan, dan filter), termasuk semua file uji yang berbeda, karena membuat modul Anda lebih dapat digunakan kembali. Jadi dalam proyek berukuran menengah saya berakhir dengan modul-dasar, yang mencakup semua rute dasar dan pengontrol, layanan, arahan dan sub-modul yang kurang lebih kompleks, ketika saya pikir mereka dapat berguna untuk proyek lain juga, misalnya :

/******** 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'
]);

Untuk proyek yang sangat besar, terkadang saya mengelompokkan modul berdasarkan rute, seperti yang dijelaskan di atas atau dengan beberapa rute utama yang dipilih atau bahkan kombinasi rute dan beberapa komponen yang dipilih, tetapi itu sangat tergantung.

EDIT: Hanya karena itu terkait dan saya bertemu lagi baru-baru ini: Berhati-hatilah karena Anda membuat modul hanya sekali (dengan menambahkan parameter kedua ke angular.module-function). Ini akan mengacaukan aplikasi Anda dan bisa sangat sulit dideteksi.

EDIT 2015 tentang modul penyortiran: Satu setengah tahun pengalaman bersudut nanti, saya dapat menambahkan bahwa manfaat dari menggunakan modul dengan nama yang berbeda dalam aplikasi Anda agak terbatas karena AMD masih tidak benar-benar berfungsi dengan baik dengan Angular dan layanan, arahan, dan filter tersedia secara global dalam konteks sudut ( seperti yang dicontohkan di sini ). Meskipun demikian, masih ada manfaat semantik dan struktural dan mungkin akan membantu jika menyertakan / mengecualikan modul dengan satu baris kode yang diberi komentar masuk atau keluar.

Ini juga hampir tidak pernah masuk akal untuk memisahkan sub-modul berdasarkan jenis (mis. 'MyMapSubModule.controllers') karena mereka biasanya bergantung satu sama lain.


7
Anda tidak memerlukan IIFE (Ekspresi Fungsi Segera Diminta), alias fungsi eksekusi mandiri anonim
plus-

1
Kamu benar. Anda hanya membutuhkannya ketika Anda ingin menerapkan bentuk-fungsi dari "gunakan ketat"; Tidak sakit.
hugo der hungrige

1
Dalam kebanyakan kasus, Anda juga dapat memasukkan ke 'use strict';dalam komponen Anda. module.controller(function () { 'use strict'; ... });
Jackson

Saya suka implementasi, tetapi saya juga tidak senang merangkai, jadi saya mencampurkan ini dengan apa yang dilakukan Beterraba
Mirko

1
saat menggunakan AMD, satu modul bernama aplikasi sudah cukup. Seseorang dapat mengecualikan modul AMD dengan menghapus pernyataan yang dibutuhkan. Dan kami tidak perlu mendaftarkan pengontrol dan layanan lagi.
Yakobus

28

Saya suka panduan gaya sudut oleh Johnpapa, dan berikut beberapa aturan yang terkait dengan pertanyaan ini:

Aturan: Fungsi Bernama vs Anonim

Hindari menggunakan fungsi anonim:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', function() { })

Sebagai gantinya, gunakan fungsi bernama:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', Dashboard);

function Dashboard() { }

Seperti yang dikatakan penulis: This produces more readable code, is much easier to debug, and reduces the amount of nested callback code.

Aturan: Tentukan 1 komponen per file.

Hindari banyak komponen dalam satu file:

angular
  .module('app', ['ngRoute'])
  .controller('SomeController', SomeController)
  .factory('someFactory', someFactory);

function SomeController() { }

function someFactory() { }

Intead, gunakan satu file untuk mendefinisikan modul:

// app.module.js
angular
  .module('app', ['ngRoute']);

satu file hanya menggunakan modul untuk mendefinisikan sebuah komponen

// someController.js
angular
  .module('app')
  .controller('SomeController', SomeController);

function SomeController() { }

dan file lain untuk menentukan komponen lain

// someFactory.js
angular
  .module('app')
  .factory('someFactory', someFactory);

function someFactory() { }

Tentu saja, ada banyak aturan lain untuk modul, pengontrol, dan layanan yang cukup berguna dan layak dibaca.

Dan terima kasih atas komentar ya_dimon, kode di atas harus dibungkus dengan IIFE, misalnya:

(function (window, angular) {
  angular.module('app')
   .controller('Dashboard', function () { });
})(window, window.angular);

Jawaban bagus dan tautan bagus.
Ellesedil

jika saya memiliki pengontrol yang berbeda dalam file javascript yang berbeda tidak akan memerlukan pemuatan lebih banyak file yaitu lebih banyak hit server?
Vignesh Subramanian

Sangat mudah untuk menggabungkan / meng-uglify / mengganti namanya dengan gulp atau grunt, vignesh, dan secara pribadi saya suka gulp.
aqingsao

1
Anda lupa menambahkan, bahwa semua cuplikan ini harus ada di IIFE, jika tidak, Anda memiliki fungsi seperti "someFactory ()" secara global. Ada kemungkinan benturan nama. (dan Anda tidak perlu IIFE di es6)
ya_dimon

12

Saya baru-baru ini juga mengalami teka-teki ini. Saya telah memulai seperti Anda menggunakan sintaks yang dirantai, tetapi dalam jangka panjang hal itu menjadi berat dengan proyek-proyek besar. Biasanya saya akan membuat modul pengontrol, modul layanan dan seterusnya dalam file terpisah dan menyuntikkannya ke modul aplikasi utama saya yang ditemukan di file lain. Sebagai contoh:

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

Tapi masing-masing file ini semakin besar seiring dengan pertumbuhan proyek. Jadi saya memutuskan untuk memecahnya menjadi file terpisah berdasarkan masing-masing pengontrol atau layanan. Saya menemukan bahwa menggunakan angular.module('mod-name').tanpa array injeksi, adalah apa yang Anda butuhkan agar ini berfungsi. Mendeklarasikan variabel global dalam satu file dan mengharapkannya tersedia di file lain tidak akan berfungsi atau dapat memberikan hasil yang tidak diharapkan.

Jadi singkatnya aplikasi saya terlihat seperti ini:

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

Saya melakukan ini ke file layanan juga, tidak perlu mengubah file modul aplikasi utama Anda masih akan menyuntikkan modul yang sama ke dalamnya.


1
apa gunanya membuat modul terpisah untuk services / directives / controllers?
Filip Sobczak

2
Dalam proyek-proyek besar, hal-hal dapat menjadi sulit untuk ditemukan ketika pengontrol / filter / arahan / layanan semuanya disatukan. Ini hanyalah salah satu cara untuk mengatur segala sesuatunya.
meconroy

1
@FilipSobczak Dia TIDAK membuat modul terpisah untuk layanan / arahan / pengontrol. Sebaliknya, dia telah membuat modul hanya sekali menggunakan angular.module('my-controllers',[]);(Perhatikan bahwa dia menentukan [] hanya sekali untuk deklarasi). Dia hanya menggunakan kembali ini di file lain. Pemisahan file membuatnya relatif mudah untuk memelihara proyek, terutama yang besar.
Devner

8

Praktik lainnya adalah memasukkan pengontrol, arahan, dll ke dalam modul mereka sendiri dan memasukkan modul tersebut ke modul "utama" Anda:

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'
]);

Tidak ada yang tersisa dalam lingkup global.

http://plnkr.co/edit/EtzzPRyxWT1MkhK7KcLo?p=preview


Mengapa Anda menggunakan app.controllersinsted of controllerssebagai nama modul, Apakah ada keuntungan? Saya seorang pendatang baru di Angularjs
sijo vijayan

4

Saya suka membagi file dan modul saya.

Sesuatu seperti ini:

app.js

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

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

directives.js

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

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

service.js

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

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

Saya bukan penggemar berat "gaya berantai", jadi saya lebih suka menuliskan variabel saya selalu.


2
Ini adalah cara saya melakukannya tetapi, setiap file services.js atau controller.js menjadi besar dengan cepat dalam proyek skala besar, akhirnya Anda harus memecah setiap layanan atau pengontrol ke file terpisah.
meconroy

1
@royalitasari Ketika sesuatu menjadi lebih besar dan lebih besar, saya suka memecah direktif menjadi modul yang lebih kecil dan kemudian menyuntikkannya ke modul direktif "utama".
Beterraba


0

Bagi saya, merangkai adalah cara paling ringkas:

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

Dengan cara itu saya dapat dengan mudah memindahkan komponen antar modul, tidak perlu mendeklarasikan modul yang sama dua kali, tidak memerlukan variabel global.

Dan jika file terlalu panjang, solusinya sederhana - pisahkan menjadi dua file, masing-masing mendeklarasikan modulnya sendiri di bagian atas. Untuk transparansi lebih, saya mencoba untuk menyimpan satu modul unik per file dan menamainya menyerupai path lengkap dari file tersebut. Dengan cara ini juga saya tidak perlu menulis modul tanpa [], yang merupakan masalah umum.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.