AngularJS thực hành tốt nhất để khai báo mô-đun?


115

Tôi có một loạt các mô-đun Angular được khai báo trong ứng dụng của mình. Ban đầu tôi bắt đầu khai báo chúng bằng cú pháp "chuỗi" như sau:

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

Nhưng tôi quyết định rằng nó không dễ đọc lắm, vì vậy tôi bắt đầu khai báo chúng bằng cách sử dụng một biến mô-đun như sau:

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

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

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

Cú pháp thứ hai có vẻ dễ đọc hơn đối với tôi, nhưng khiếu nại duy nhất của tôi là cú pháp này làm modbiến mất trong phạm vi toàn cục. Nếu tôi có một số biến khác được đặt tênmod , nó sẽ bị ghi đè với biến tiếp theo này (và các vấn đề khác liên quan đến biến toàn cục).

Vì vậy, câu hỏi của tôi là, đây có phải là cách tốt nhất? Hay sẽ tốt hơn nếu làm điều gì đó như thế này ?:

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

Hay nó thậm chí có đủ quan trọng để quan tâm? Chỉ tò mò muốn biết "phương pháp hay nhất" để khai báo mô-đun là gì. Cảm ơn trước.


3
Tôi tự hỏi điều tương tự về Các phương pháp hay nhất
Dalorzo

Câu trả lời:


118

Cách 'tốt nhất' để khai báo một mô-đun

Vì góc nằm trên phạm vi toàn cục và các mô-đun được lưu vào biến của nó, bạn có thể truy cập các mô-đun thông qua 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){
      //..
  }])
})();

Không có biến toàn cục nào khác được yêu cầu.

Tất nhiên, tất cả phụ thuộc vào sở thích, nhưng tôi nghĩ đây là loại phương pháp hay nhất, như

  1. bạn không phải gây ô nhiễm phạm vi toàn cầu
  2. bạn có thể truy cập các mô-đun của mình ở mọi nơi và sắp xếp chúng cũng như các chức năng của chúng thành các tệp khác nhau theo ý muốn
  3. bạn có thể sử dụng dạng hàm "sử dụng nghiêm ngặt";
  4. thứ tự tải các tệp không quan trọng bằng

Các tùy chọn để sắp xếp các mô-đun và tệp của bạn

Cách khai báo và truy cập module này giúp bạn rất linh hoạt. Bạn có thể sắp xếp các mô-đun thông qua kiểu hàm (như được mô tả trong một câu trả lời khác) hoặc qua tuyến đường, ví dụ:

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

Cuối cùng thì bạn sắp xếp nó như thế nào là vấn đề của sở thích cá nhân và quy mô cũng như loại dự án. Cá nhân tôi muốn nhóm tất cả các tệp của một mô-đun bên trong cùng một thư mục (được sắp xếp thành các thư mục con gồm chỉ thị, bộ điều khiển, dịch vụ và bộ lọc), bao gồm tất cả các tệp thử nghiệm khác nhau, vì nó làm cho mô-đun của bạn có thể tái sử dụng nhiều hơn. Vì vậy, trong các dự án quy mô trung bình, tôi kết thúc với một mô-đun cơ sở, bao gồm tất cả các tuyến cơ bản và bộ điều khiển, dịch vụ, chỉ thị và nhiều mô-đun con phức tạp hơn hoặc ít phức tạp hơn, khi tôi nghĩ chúng cũng có thể hữu ích cho các dự án khác, ví dụ: :

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

Đối với các dự án rất lớn, đôi khi tôi kết thúc nhóm các mô-đun theo các tuyến, như đã mô tả ở trên hoặc theo một số tuyến chính được chọn hoặc thậm chí kết hợp các tuyến và một số thành phần đã chọn, nhưng nó thực sự phụ thuộc.

CHỈNH SỬA: Chỉ vì nó có liên quan và gần đây tôi lại gặp phải vấn đề đó: Hãy cẩn thận để bạn tạo một mô-đun chỉ một lần (bằng cách thêm tham số thứ hai vào hàm angle.module-). Điều này sẽ làm rối ứng dụng của bạn và có thể rất khó phát hiện.

2015 CHỈNH SỬA về phân loại mô-đun: Một năm rưỡi trải nghiệm góc sau đó, tôi có thể nói thêm rằng những lợi ích từ việc sử dụng các mô-đun được đặt tên khác nhau trong ứng dụng của bạn hơi hạn chế vì AMD vẫn không thực sự hoạt động tốt với Angular và các dịch vụ, chỉ thị và bộ lọc vẫn có sẵn trên toàn cầu bên trong ngữ cảnh góc cạnh ( như được ví dụ ở đây ). Mặc dù vậy, vẫn có một lợi ích về ngữ nghĩa và cấu trúc và nó có thể hữu ích khi có thể bao gồm / loại trừ một mô-đun với một dòng mã duy nhất được nhận xét trong hoặc ngoài.

Nó cũng hầu như không bao giờ có ý nghĩa khi tách các mô-đun con theo loại (ví dụ: 'myMapSubModule.controllers') vì chúng thường phụ thuộc vào nhau.


7
Bạn không cần IIFE (Biểu thức hàm được gọi ngay lập tức), hay còn gọi là hàm tự thực thi ẩn danh
plus-

1
Bạn đúng. Bạn chỉ cần nó khi bạn muốn áp dụng dạng hàm "sử dụng nghiêm ngặt"; Không đau.
hugo der hungrige

1
Trong hầu hết các trường hợp, bạn cũng có thể đặt 'use strict';bên trong thành phần của mình. module.controller(function () { 'use strict'; ... });
Jackson

Tôi như thực hiện, nhưng tôi không phải là một niềm vui của chaining hoặc, vì vậy tôi đang trộn này với những gì đang làm Beterraba
Mirko

1
khi sử dụng AMD, một ứng dụng có tên mô-đun đơn là đủ. Người ta có thể loại trừ một mô-đun AMD bằng cách xóa câu lệnh request. Và chúng tôi không cần đăng ký bộ điều khiển và dịch vụ nữa.
James

28

Tôi thích hướng dẫn kiểu góc cạnh của Johnpapa và đây là một số quy tắc liên quan đến câu hỏi này:

Quy tắc: Được đặt tên so với Hàm ẩn danh

Tránh sử dụng các chức năng ẩn danh:

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

Thay vào đó, hãy sử dụng các hàm được đặt tên:

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

function Dashboard() { }

Như tác giả nói: This produces more readable code, is much easier to debug, and reduces the amount of nested callback code.

Quy tắc: Xác định 1 thành phần trên mỗi tệp.

Tránh nhiều thành phần trong một tệp:

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

function SomeController() { }

function someFactory() { }

Intead, sử dụng một tệp để xác định mô-đun:

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

một tệp chỉ sử dụng mô-đun để xác định một thành phần

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

function SomeController() { }

và một tệp khác để xác định một thành phần khác

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

function someFactory() { }

Tất nhiên, có nhiều quy tắc khác cho các mô-đun, bộ điều khiển và dịch vụ khá hữu ích và đáng đọc.

Và nhờ nhận xét của ya_dimon, đoạn mã trên nên được gói trong IIFE, ví dụ:

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

Câu trả lời tốt và liên kết tuyệt vời.
Ellesedil

Nếu tôi có các bộ điều khiển khác nhau trong các tệp javascript khác nhau, nó sẽ không yêu cầu tải nhiều tệp hơn tức là nhiều lần truy cập máy chủ hơn?
Vignesh Subramanian

Thật dễ dàng để hợp nhất / uglify / đổi tên chúng bằng gulp hoặc grunt, vignesh, và cá nhân tôi thích gulp.
aqingsao

1
bạn đã quên thêm rằng tất cả các đoạn mã này phải nằm trong IIFE, nếu không bạn có các hàm như "someFactory ()" trên toàn cầu. Có cơ hội xảy ra va chạm tên tuổi. (và bạn không cần IIFE trong es6)
ya_dimon

12

Gần đây tôi cũng có câu hỏi hóc búa này. Tôi đã bắt đầu giống như bạn bằng cách sử dụng cú pháp chuỗi, nhưng về lâu dài, nó trở nên khó sử dụng với các dự án lớn. Thông thường, tôi sẽ tạo một mô-đun bộ điều khiển, một mô-đun dịch vụ, v.v. trong các tệp riêng biệt và đưa chúng vào mô-đun ứng dụng chính của tôi được tìm thấy trong một tệp khác. Ví dụ:

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

Nhưng mỗi một trong số các tệp này ngày càng lớn khi dự án phát triển. Vì vậy, tôi quyết định chia chúng thành các tệp riêng biệt dựa trên từng bộ điều khiển hoặc dịch vụ. Tôi thấy rằng sử dụng angular.module('mod-name').mà không có mảng tiêm, là những gì bạn cần để điều này hoạt động. Khai báo một biến toàn cục trong một tệp và mong đợi biến đó sẵn có trong tệp khác sẽ không hoạt động hoặc có thể có kết quả không mong muốn.

Tóm lại, ứng dụng của tôi trông giống như sau:

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

Tôi cũng đã thực hiện việc này với tệp dịch vụ, không cần thay đổi tệp mô-đun ứng dụng chính mà bạn vẫn sẽ đưa các mô-đun tương tự vào đó.


1
lợi ích của việc tạo các mô-đun riêng biệt cho các dịch vụ / chỉ thị / bộ điều khiển là gì?
Filip Sobczak

2
Trong các dự án lớn, mọi thứ có thể khó tìm thấy khi tất cả các bộ điều khiển / bộ lọc / chỉ thị / dịch vụ được xen kẽ với nhau. Đây chỉ là một cách để giữ mọi thứ ngăn nắp.
meconroy

1
@FilipSobczak Anh ấy KHÔNG tạo các mô-đun riêng biệt cho các dịch vụ / chỉ thị / bộ điều khiển. Đúng hơn, anh ta đã tạo mô-đun chỉ một lần bằng cách sử dụng angular.module('my-controllers',[]);(Lưu ý rằng anh ta chỉ định [] một lần duy nhất để khai báo). Anh ta chỉ đơn giản là sử dụng lại cái này trong các tệp khác. Việc phân tách các tệp giúp cho việc duy trì dự án tương đối dễ dàng, đặc biệt là những tệp lớn.
Devner

8

Một cách thực hành khác là nhồi nhét bộ điều khiển, chỉ thị, v.v. vào các mô-đun của riêng chúng và đưa các mô-đun đó vào mô-đun "chính" của bạn:

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

Không có gì còn lại trong phạm vi toàn cầu.

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


Tại sao bạn sử dụng app.controllersinsted of controllerslàm tên mô-đun, Có lợi thế nào không? Tôi là một người mới trong Angularjs
SIJO Vijayan

4

Tôi muốn phân chia các tệp của tôi và các mô-đun của tôi.

Một cái gì đó như thế này:

app.js

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

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

chỉ thị.js

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

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

service.js

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

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

Tôi không phải là một fan hâm mộ lớn của "phong cách chuỗi", vì vậy tôi muốn viết ra biến của tôi luôn luôn.


2
Đây là cách tôi đã làm nhưng mỗi tệp services.js hoặc controller.js trở nên nhanh chóng trong một dự án quy mô lớn, cuối cùng bạn sẽ cần chia từng dịch vụ hoặc bộ điều khiển ra một tệp riêng biệt.
meconroy

1
@meconroy Chính xác. Khi mọi thứ ngày càng trở nên lớn hơn, tôi muốn chia chỉ thị thành các mô-đun nhỏ hơn và sau đó đưa vào mô-đun chỉ thị "chính".
Beterraba


0

Đối với tôi, chuỗi là cách nhỏ gọn nhất:

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

Bằng cách đó, tôi có thể dễ dàng di chuyển các thành phần giữa các mô-đun, không bao giờ cần phải khai báo cùng một mô-đun hai lần, không bao giờ cần bất kỳ biến toàn cục nào.

Và nếu tệp quá dài, giải pháp rất đơn giản - chia thành hai tệp, mỗi tệp khai báo mô-đun riêng ở trên cùng. Để rõ ràng hơn, tôi cố gắng giữ một mô-đun duy nhất cho mỗi tệp và đặt tên nó giống với đường dẫn đầy đủ của tệp. Bằng cách này, tôi không bao giờ cần phải viết một mô-đun mà không có [], đó là một điểm phổ biến.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.